認識無鎖隊列

無鎖隊列是 lock-free 中最基本的數據結構,一般應用在需要一款高性能隊列的場景下。

對於多線程用戶來說,無鎖隊列的入隊和出隊操作是線程安全的,不用再加鎖控制。

什麼是無鎖隊列

隊列每個開發者都知道,那麼什麼又是無鎖隊列呢?字面理解起來就是一個無鎖狀態的隊列,多個線程(消費者)同時操作數據的時候不需要加鎖,因爲加/解鎖都是一個很消耗資源的動作。

數據結構

我們先看一下無鎖隊列的底層實現數據結構。

無鎖隊列底層的數據結構實現方式主要有兩種:數組 和 鏈接。

數組

在首次初始化時,需要申請一塊連接的大的內存。讀寫數據直接從數據的指定位置操作即可,時間複雜度爲O(1)。

缺點:數組長度有限,一旦數組索引位置寫滿,則無法繼續寫入,即隊列有上限。

鏈表

不用像數組一樣,剛開始就申請一塊連接的大的內存空間。只有在每次寫時數據的時候,申請這個數據節點大小的內存即可,這樣就可以實現無限的寫入,沒有長度限制問題。

缺點:每次寫數據都要申請內存,在寫的場景,最差的情況是多少個數據就申請多少次內存,而每次申請都是一個消耗資源的動作。

可以看到無鎖底層的實現的不同各有優勢。多數據情況下,我們都採用鏈表來實現無鎖隊列,主要原因就是寫入可以沒有長度的限制。相比每次申請都要費時來說,滿足前面的條件是我們最基本的要求。當然主要還是真正的使用場景。

CAS

CAS 是 Compare And Swap 的簡稱, 屬於 樂觀鎖,這是一個併發同步原語. 僞代碼如下:

bool compare_and_swap(int *reg, int oldval, int newval)
{
    int reg_val = *reg;
    if(reg_val == oldval)
    {
        *reg = newval;
        return true;
    }
    return false;
}

CAS操作有三個參數,分別表示 內存值V、舊的預期值A 和 修改後的更新值B。

判斷變量內存某個位置的值是否爲預期值,如果是則更改爲新的值,並返回true,這個過程是原子性操作。如果修改失敗,可能需要重試再次執行CAS操作,直到修改成功,一般稱此過程爲自旋。可以看到每次調用 CAS 命令前需要先讀取舊值 oldval。

現在幾乎所有的CPU指令都支持CAS的原子操作,X86下對應的是 CMPXCHG 彙編指令。有了這個操作,我們就可以用其來實現各種無鎖的數據結構。

使用場景

無鎖隊列也屬於隊列的一種,所以大部分隊列的使用場景都可以使用它來代替其它有鎖隊列,無鎖隊列通過不加鎖的方式提高隊列性能。

本文地址:https://www.linuxprobe.com/understanding-lockless-queue.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章