多執行緒的那點兒事(之無鎖鏈表)
阿新 • • 發佈:2019-02-20
【 宣告:版權所有,歡迎轉載,請勿用於商業用途。 聯絡信箱:feixiaoxing @163.com】
前面,為了使得寫操作快速進行,我們定義了順序鎖。但是順序鎖有個缺點,那就是處理的資料不能是指標,否則可能會導致exception。那麼有沒有辦法使得處理的資料包括指標呢?當然要是這個連結串列沒有鎖,那就更好了。
針對這種無鎖鏈表,我們可以初步分析一下,應該怎麼設計呢?
(1)讀操作沒有鎖,那麼怎麼判斷讀操作正在進行呢,只能靠標誌位了;
(2)寫操作沒有鎖,那麼讀操作只能一個執行緒完成;
(3)寫操作中如果是新增,那麼直接加在末尾即可;
(4)寫操作中如果是刪除,那麼應該先刪除資料,然後等到當前沒有操作訪問刪除資料時,釋放記憶體,但是首節點不能刪除。
普通連結串列的結構為,
typedef struct _LINK
{
int data;
struct _LINK* next;
}LINK;
假設此時有32個執行緒在訪問連結串列,那麼可以定義一個全域性變數value,每一個bit表示一個thread,讀操作怎麼進行呢,
那麼,寫操作怎麼進行呢,void read_process() { int index = get_index_from_threadid(GetThreadId()); InterLockedOr(&value, 1 << index); /* read operation */ InterLockedAnd(&value, ~(1<< index)); }
其中連結串列的刪除操作為,void write_process_add(LINK* pHead, LINK* pLink) { /* add link to the tail of list */ } void write_process_del(LINK* pHead, LINK* pLink) { delete_link_from_list(pHead, pLink); while(1){ if(0 == value) break; Sleep(100); } free(pLink); }
/*
* From:
* -> a -> b -> c -> d
*
* To:
* -----------------
* | V
* -> a b -> c ->d
*
*/
總結:
(1)這種無鎖鏈表有很多侷限:多讀少寫、注意使用原子操作、不能刪除頭結點、資料只能新增到尾部、注意刪除順序和方法、讀執行緒個數有限制等等;
(2)寫操作在操作前需要等待所有的讀操作,否則有可能發生異常;
(3)寫操作不能被多個執行緒使用;
(4)無鎖鏈表應用範圍有限,只是特殊情況下的一種方案而已。