簡體   English   中英

C ++ 11使用<atomic>實現Spinlock

[英]C++11 Implementation of Spinlock using <atomic>

我實現了SpinLock類,如下所示

struct Node {
    int number;
    std::atomic_bool latch;

    void add() {
        lock();
        number++;
        unlock();
    }
    void lock() {
        bool unlatched = false;
        while(!latch.compare_exchange_weak(unlatched, true, std::memory_order_acquire));
    }
    void unlock() {
        latch.store(false , std::memory_order_release);
    }
};

我實現了上面的類,並創建了兩個線程,每個線程調用一個相同的Node類實例的add()方法1000萬次。

不幸的是,結果不是2000萬。 我在這里錯過了什么?

問題是compare_exchange_weak一旦失敗就會更新unlatched變量。 compare_exchange_weak的文檔:

將原子對象包含的值的內容與預期值進行比較: - 如果為true,則用val替換包含的值(如store)。 - 如果為false,則將其替換為包含的值。

即第一失敗后compare_exchange_weakunlatched將更新為true ,那么下一個循環周期將嘗試compare_exchange_weak truetrue 這成功了,你只是拿了一個由另一個線程持有的鎖。

解決方案:確保設置unlatchedfalse每個前compare_exchange_weak ,如:

while(!latch.compare_exchange_weak(unlatched, true, std::memory_order_acquire)) {
    unlatched = false;
}

正如@gexicide所提到的,問題是compare_exchange函數使用原子變量的當前值更新expected變量。 這也是為什么你必須首先使用未unlatched的局部變量的原因。 要解決此問題,您可以在每次循環迭代中將unlatched設置為false。

但是,使用std::atomic_flag來代替使用compare_exchange ,而不是使用compare_exchange ,它更適合使用std::atomic_flag

class SpinLock {
    std::atomic_flag locked = ATOMIC_FLAG_INIT ;
public:
    void lock() {
        while (locked.test_and_set(std::memory_order_acquire)) { ; }
    }
    void unlock() {
        locked.clear(std::memory_order_release);
    }
};

資料來源: cppreference

手動指定內存順序只是一個次要的潛在性能調整,我從源代碼復制。 如果簡單性比最后一點性能更重要,您可以堅持使用默認值並只調用locked.test_and_set() / locked.clear()

順便說一句: std::atomic_flag是唯一保證無鎖的類型,雖然我不知道任何平台, std::atomic_bool上的std::atomic_bool不是免費的。

更新:正如@David Schwartz,@ Anton和@Technik Empire的評論中所解釋的那樣,空循環有一些不良影響,如分支未預測,HT處理器上的線程飢餓和過高的功耗 - 所以簡而言之,這是一個非常低效的等待的方式。 影響和解決方案是架構,平台和應用程序特定的。 我不是專家,但通常的解決方案似乎是在linux上添加cpu_relax()或在循環體上添加窗口上的YieldProcessor()

EDIT2:為了清楚起見:這里提供的便攜版本(沒有特殊的cpu_relax等指令)應該足以滿足許多應用程序的要求。 如果你的SpinLock旋轉很多,因為其他人持有鎖很長時間(這可能已經表明一般的設計問題),最好還是使用普通的互斥鎖。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM