正如其他答案指出的,不,++不是「線程安全」。
當您瞭解多線程及其危害時,我認爲有助於您開始非常精確地描述「線程安全」的含義,因爲不同的用戶意味着不同的東西。本質上,您所關心的線程安全方面是操作是否爲原子或不。 「原子」操作是當被另一個線程中斷時,保證不會中途完成。 (有很多其他線程問題與原子性無關,但可能仍然落在某些人對線程安全的定義之下,例如,給定兩個線程,每個線程變異一個變量,兩個線程分別讀取變量,兩個讀者是否保證同意訂單其中另外兩個線程發生了突變?如果你的邏輯依賴於它,那麼即使每次讀寫都是原子的,你也有一個非常難以處理的線程安全問題。 )
在C#中,幾乎沒有什麼是保證是原子的。簡言之:
- 讀取32位整數或浮點
- 讀取參考
- 寫一個32位整數或浮點
- 寫入參考
保證是原子的(見詳細說明如下)
特別是讀寫64位整數或浮點數是不是保證是原子的。如果你說:
C.x = 0xDEADBEEF00000000;
一個線程,
C.x = 0x000000000BADF00D;
在另一個線程,則有可能到第三線程:
Console.WriteLine(C.x);
有寫出來0xDEADBEEF0BADF00D,即使邏輯上該變量從未保留該值。 C#語言保留寫作的權利,等同於一次一個地寫入兩個整數,實踐中一些芯片確實以這種方式實現。第一次寫入後的線程切換可能會導致讀者讀取意外的內容。
它的長短是:不要分享什麼東西兩個線程之間沒有鎖定的東西。滿足時鎖只是緩慢的;如果因爲競爭鎖定而出現性能問題,則可修復造成鎖定的任何體系結構缺陷。如果鎖不競爭並且速度太慢,那麼只有在這種情況下才應該考慮採用危險的低鎖技術。
這裏使用的常見低鎖定技術當然是調用Threading.Interlocked.Increment
,它以保證爲原子的方式增加整數。 (但是請注意,它仍然不能保證如果兩個線程在不同時間執行兩個不同變量的互鎖遞增,而其他線程正在嘗試確定哪個增量「首先」發生時會發生什麼事情,C#不保證所有線程都可以看到一致的事件順序。)
這裏是[另一個Eric](http://blog.decarufel.net/2009/02/why-operator-is-not-thread-safe.html),它解釋了爲什麼`++`操作符不是線程安全。關鍵是CPU不能直接在內存中進行數學運算 - 它必須先將內存中的值加載到寄存器中;這造成了競爭條件的可能性。使用多線程編程時需要注意的一點是,一般情況下,除非文檔*明確地告訴你它們是否是這樣,否則應該假設事情不是**線程安全的。 – 2011-01-07 17:23:42