2015-04-02 69 views
6

我很困惑這個問題 - 讀/切換布爾值是否線程安全。C#和線程安全的bool

// case one, nothing 
    private bool v1; 
    public bool V1 { get { return v1; } set { v1 = value; } } 

    // case two, with Interlocked on set 
    private int v2; 
    public int V2 { get { return v2; } set { Interlocked.Exchange(ref v2, value); } } 

    // case three, with lock on set 
    private object fieldLock = new object(); 
    private bool v3; 
    public bool V3 { get { return v3; } set { lock (fieldLock) v3 = value; } } 

他們都是線程安全的嗎?

編輯

從我讀(click)布爾的原子並不保證它是線程安全的。請問volatile型的幫助?

+1

這些都不是線程安全的。調用getter的線程將始終讀取陳舊值。它有多陳舊取決於處理器和優化器。從幾納秒到無窮大。吸氣劑也需要同步。或者你可以使用ManualResetEvent/Slim。 – 2015-04-02 12:26:51

+0

@ Ksv3n * Assignement總是一個原子操作*假,32位程序的「長」(64位)分配不是原子的。 – xanatos 2015-04-02 13:00:24

+0

@HansPassant一個getter可以讀取一箇舊值,這是可以理解的。但是,它怎麼會持續到無窮?使用鎖將使它讀取*正確*值 - 重讀它,就好像它是不穩定的?我不認爲它是這樣工作的,我對你說的話感到困惑。我認爲一旦沒有人在寫東西,吸氣劑就會正常工作。 – 2015-04-02 13:40:58

回答

12

不,不是所有的都是線程安全的。

第一種情況實際上並不完全是線程安全的,或者更好的說法 - 它根本不是線程安全的。即使布爾操作是原子操作,變量值也可以存儲在緩存中,因此,如同多核CPU一樣,每個核心都有它自己的緩存,可能會損壞值。編譯器和CPU可以執行一些內部優化,包括指令重新排序,這可能會對程序的邏輯造成不利影響。

您可以添加volatile關鍵字,以通知編譯器該字段在多線程環境中使用。它將解決高速緩存和指令重新排序問題,但不會爲您提供真正的「線程安全」代碼(因爲寫入操作仍然不會同步)。另外volatile不能應用於局部變量。

因此,在處理多線程時,您總是必須使用一些線程同步技術來處理有價值的資源。

欲瞭解更多信息 - 請閱讀this答案,其中有一些更深入的解釋不同的技術。 (例如大約有int,但實際上並不重要,它描述了一般方法。)

+3

*值可能被破壞*否,值不能被破壞(如在「轉換非法/未定義的值」)。你可能會陳舊(「舊」)值。 – xanatos 2015-04-02 12:58:38

+0

我的意思是「腐敗」的方式「不是一個,它應該或你期望它是」。絕對不是在內存腐敗的意義上的損壞:) – Yura 2015-04-02 15:26:03