多執行緒無鎖演算法之無鎖佇列的實現

2021-06-22 17:29:07 字數 2354 閱讀 9621

今天花了近兩個小時的時間好好的理解了一下多執行緒無鎖佇列的實現,檢視了很多資料和文獻。在我看來,實現無鎖佇列的關鍵點有二:

1、各個平台的原子操作或者說cas原語;

2、aba問題的理解和解決。

首先來說說這個cas原語,所謂cas(compare and swap)即比較並交換,在 intel 處理器中,比較並交換通過指令的 cmpxchg 系列實現。cas有三個運算元: 記憶體位置(v)、預期原值(a)和新值(b)。如果記憶體位置v的值與預期a原值相匹配,那麼處理器會自動將該位置值更新為新值b。否則,處理器不做任何操作。無論哪種情況,它都會在 cas 指令之前返回該位置的值。(在 cas 的一些特殊情況下將僅返回 cas 是否成功,而不提取當前值。)cas 有效地說明了「我認為位置 v 應該包含值 a;如果包含該值,則將 b 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可。」cas的c語言實現如下:

inline bool cas2(pointer_t *addr, pointer_t &old_value, pointer_t &new_value)

這其中包括了內聯彙編**(這個可以去看看at&t彙編語法),其中能夠支援多執行緒的並行安全執行的秘訣就在 "lock cmpxchg16b %1;\n"這句中的「lock」,這個lock就和我們基本多執行緒程式設計中的鎖相當,只不過,這個lock不再是普通的鎖,它鎖的是位址匯流排,在多核程式設計情景下,當已經有cpu的執行緒a已經訪問某位址時,這時位址匯流排會被鎖定,其他cpu核心的執行緒b無法再訪問當前位址,直到a訪問完畢之後,其他執行緒如b才可能訪問該位址,這樣就保證了執行緒a訪問該位址的原子性操作。

再來講講這個aba問題。在進行cas操作時,因為在更改v值之前,cas主要是通過訪問v的值是否仍然和a相等,所以,在第一次讀取v以及對v執行cas操作之前,如果有其他執行緒將v的值先從a改為b,而另外的執行緒又將v的值從b改回了a,這樣會使cas演算法混亂。顯然,在這種情況下,cas的操作會成功,這類的問題稱為aba問題。要解決這類問題,就是不再重用a,通常的做法是用標記或版本編號與進行cas操作的每個值相關聯,並原子的更新值和標記(如果有的朋友還不夠清楚,可以上網搜搜aba問題,呵呵……)。

在了解了以上兩點後,就可以著手來設計和實現無鎖佇列了。為了保證正確性,我就不把自己的**貼出來了,再網上找了乙個,和我自己的差不多,但是,免得誤導有些朋友,我貼了個網上的,這個佇列是ms-queue的實現,有興趣的朋友,可以去網上查查哦,一大把的例子,呵呵,我貼到這裡很大一部分原因是為了備忘,呵呵……

ms-queue c++ / c的實現:

#ifndef __lock_free_queue_hpp__

#define __lock_free_queue_hpp__

#include struct node_t;

struct pointer_t

pointer_t(node_t *a_ptr, unsigned int a_tag)

friend

bool operator==(pointer_t const &l, pointer_t const &r)

friend

bool operator!=(pointer_t const &l, pointer_t const &r)

};typedef void * data_type;

#define dummy_val null

struct node_t

};#ifdef __x86_64__

inline bool cas2(pointer_t *addr,

pointer_t &old_value,

pointer_t &new_value)

#else

inline bool cas2(pointer_t *addr,

pointer_t &old_value,

pointer_t &new_value)

#endif

class queue_t

void init()

void enqueue(data_type val)

}else }}

pointer_t new_pt(nd, tail.tag+1);

cas2(&(this->tail_), tail, new_pt);

}data_type dequeue()

pointer_t new_pt(next.ptr, tail.tag+1);

cas2(&(this->tail_), tail, new_pt);

} else}}

delete head.ptr;

return val;}};

#endif //__lock_free_queue_hpp__

多執行緒無鎖演算法之無鎖佇列的實現

今天花了近兩個小時的時間好好的理解了一下多執行緒無鎖佇列的實現,檢視了很多資料和文獻。在我看來,實現無鎖佇列的關鍵點有二 1 各個平台的原子操作或者說cas原語 2 aba問題的理解和解決。首先來說說這個cas原語,所謂cas compare and swap 即比較並交換,在 intel 處理器中...

多執行緒的那點兒事(之無鎖佇列)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!對於編寫多執行緒的朋友來說,佇列具有天生的互斥性。在佇列裡面,乙個負責新增資料,乙個負責處理資料。誰也不妨礙誰,誰也離不開誰。所以,佇列具有天生的並行性。define max number 1000l define status int defin...

多執行緒的那點兒事14(之無鎖佇列)

對於編寫多執行緒的朋友來說,佇列具有天生的互斥性。在佇列裡面,乙個負責新增資料,乙個負責處理資料。誰也不妨礙誰,誰也離不開誰。所以,佇列具有天生的並行性。cpp view plain copy define max number 1000l define status int define ok 0...