簡體   English   中英

以下 C ++ 代碼中實現的 DCL(雙重檢查鎖定)是否是線程安全的?

[英]Is the DCL(double-checked locking) implemented in the following C ++ code thread-safe?

這是一段由 C++ 中的“獲取-釋放”語義實現的 DCL(雙重檢查鎖定)代碼。 代碼如下:

std :: atomic <Singleton *> Singleton :: m_instance;
std :: mutex Singleton :: m_mutex;

Singleton * Singleton :: getInstance () {
    Singleton * tmp = m_instance.load (std :: memory_order_acquire); // 3
    if (tmp == nullptr) {
        std :: lock_guard <std :: mutex> lock (m_mutex);
        tmp = m_instance.load (std :: memory_order_relaxed);
        if (tmp == nullptr) {
            tmp = new Singleton; // 1
            m_instance.store (tmp, std :: memory_order_release); // 2
        }
    }
    return tmp;
}

https://en.cppreference.com/w/cpp/atomic/memory_order上,memory_order_release 的解釋是:使用此 memory 命令的存儲操作執行釋放操作:在此之后不能重新排序當前線程中的讀取或寫入店鋪。 當前線程中的所有寫入在獲取相同原子變量的其他線程中都是可見的。

我的理解是:load-store,store-store不能重排,但沒說other-store不能重排。

所以我認為:'1'不僅包括讀寫指令,還包括調用指令,那么調用指令可能在'2'后面重新排序; 那么'3'可能會得到一個不安全的'tmp'指針。

讓我再描述一下上面的段落:

Disassemble ‘1’ into the following two possible pseudo-instructions:
tmp = allocate ();
call Singleton constructor (tmp); // 4

我認為“4”可能會在“2”之后重新排序。 在一個線程執行'2'后,另一個線程完成'3'並獲得tmp指針。 此時tmp指針是一個不安全的Singleton指針。

所以我有這個問題:上面的代碼是線程安全的嗎?

是的,它是安全的!

如果獲取加載返回 null(即 singleton 尚未初始化),則您獲取互斥鎖。 在互斥體內部,重新加載可以放松,因為m_instance的修改無論如何都受到互斥體的保護,即,如果某個其他線程已經初始化了 singleton,那么該線程的互斥釋放必須在我們的互斥獲取操作之前發生,所以可以保證我們看到更新的m_instance

如果 acquire-load (1) “看到” release-store (2) 寫入的值,這兩個操作會相互同步,從而建立起之前發生的關系,因此您可以安全地訪問 object tmp 指向的值。

更新
release-store 也受互斥體保護,tmp 的初始化部分不可能與 store 重新排序。 一般來說,應該避免爭論可能的重新排序。 該標准沒有說明是否/如何重新排序操作。 相反,它定義了(線程間)-happens-before 關系。 編譯器可能執行的任何重新排序僅僅是應用發生前關系規則的結果。

如果acquire-load (1) 加載release-store (2) 寫入的值,則這兩個操作相互同步,從而建立happens-before 關系,即(2)happens-before (3)。 但是由於 (1) 是先於 (2) 排序的,並且發生在之前的關系是可傳遞的,因此必須保證 (1) 發生在 (3) 之前。 因此,不可能用 (2) 重新排序 (1) (或它的一部分)。

暫無
暫無

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

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