1. 程式人生 > >多執行緒的那點兒事(之無鎖鏈表)

多執行緒的那點兒事(之無鎖鏈表)

【 宣告:版權所有,歡迎轉載,請勿用於商業用途。  聯絡信箱: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)無鎖鏈表應用範圍有限,只是特殊情況下的一種方案而已。