簡體   English   中英

此代碼是線程安全的嗎?

[英]Is this code thread-safe?

假設我們有一個線程安全的比較和交換功能,例如
long CAS(long * Dest ,long Val ,long Cmp)
比較DestCmp ,如果比較成功,則將Val復制到Dest ,並自動返回Dest的原始值。

所以我想問你下面的代碼是否是線程安全的。

while(true)
{
    long dummy = *DestVar;
    if(dummy == CAS(DestVar,Value,dummy) )
     {
        break;
    }

}

編輯:
Dest和Val參數是指向在堆上創建的變量的指針。 InterlockedCompareExchange是輸出CAS函數的示例。

編輯。 對問題進行編輯意味着大多數與此無關。 盡管如此,我將保留這一點,因為C#案例中的所有關注點也都包含在C ++案例中,但是C ++案例帶來了更多的關注,因此並不是完全無關緊要的。


對,但是...

假設您的意思是說這個CAS是原子的(C# Interlocked.CompareExchange就是這種情況,並且在某些C ++庫中可以使用某些東西),它本身就是線程安全的。

但是DestVar = Value本身也可以是線程安全的(無論在C ++中還是在實現中,它都將在C#中使用)。

在C#中,對整數的寫保證是原子的。 這樣,執行DestVar = Value不會因另一個線程中發生的事情而失敗。 這是“線程安全的”。

在C ++中,沒有這樣的保證,但是在某些處理器上有保證(實際上,讓我們暫時放下C ++,就更強大的C#保證而言,有足夠的復雜性,而C ++具有所有這些復雜性,而涉及到的復雜性更多)這些問題)。

現在,原子CAS操作本身的使用始終將是“安全的”,但這並不是線程安全的復雜性所在。重要的是,操作組合的線程安全。

在您的代碼中,在每個循環中,該值要么被原子覆蓋,要么不會被覆蓋。 如果無法使用,它將再次嘗試並繼續嘗試直到成功為止。 它可能最終會旋轉一段時間,但最終會起作用。

這樣做的效果與簡單分配完全相同-包括弄亂另一個線程中發生的事情並導致嚴重的線程相關錯誤的可能性。

為了進行比較,請看一下下面的答案, 這是否使用靜態隊列線程安全? 以及它是如何工作的。 請注意,在每種情況下,CAS都可能因失敗而失敗,因為它的失敗意味着另一個線程做了“有用的事”,或者當檢查成功時,不僅僅是停止循環而已。 它是CAS的組合,每個CAS都注意由其他操作導致的可能狀態,這些其他操作允許使用線程安全的無鎖免等待代碼。

現在,我們已經完成了此操作,還請注意,您無法將其直接移植到C ++(它依賴於垃圾回收,以使某些可能的ABA場景產生的影響很小,而C ++則存在內存泄漏的情況)。 您說的是哪種語言也確實很重要。

在任何環境下都無法分辨。 您沒有定義以下內容:

  • DestVarValue的存儲位置是什么? 在堆還是堆棧上? 如果它們在堆棧上,那么它是線程安全的,因為沒有其他線程可以訪問該內存位置。

  • 如果DestVarValue在堆上,那么它們是引用類型還是值類型(具有按分配語義復制)。 如果是后者,則是線程安全的。

  • CAS是否同步對其自身的訪問? 換句話說,它是否具有某種互斥結構,一次只能允許一個呼叫? 如果是這樣,則它是線程安全的。

  • 如果上述任何條件都不成立,則不確定是否所有線程安全。 有了有關上述條件的更多信息(以及這是否為C ++或C#, 是的,這確實很重要 ),就可以提供答案。

實際上,此代碼有點破損。 您可能需要知道編譯器如何讀取*DestVar (在CAS之前或之后),它具有截然不同的語義,或者您試圖在*DestVar上旋轉直到其他線程對其進行了更改。 當然不是前者,因為那太瘋狂了。 如果是后者,則應使用原始代碼。 就目前而言,您的修訂版不是線程安全的,因為它根本不安全。

暫無
暫無

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

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