2011-07-01 44 views
11

如果一個32位變量在多個線程之間共享,我應該在變量周圍放置一個互斥鎖嗎?例如,假設1個線程寫入32位計數器,第2個線程讀取它。第二個線程是否有可能讀取損壞的值?我應該互斥鎖定一個變量嗎?

我正在使用32位ARM嵌入式系統。編譯器似乎總是對齊32位變量,因此它們可以用一條指令讀取或寫入。如果32位變量未對齊,則讀取或寫入將分解爲多條指令,第二個線程可能讀取損壞的值。

如果我將來轉移到多核系統並且變量在覈心之間共享,這個問題的答案是否會發生變化? (假設核心之間共享緩存)

謝謝!

+3

你關心比賽,還是隻關心撕裂? –

+2

一旦你滿意自己撕裂沒有發生,記住不要寫'i ++'或者'i + = j'沒有互斥體。 –

+1

感謝關於撕裂的評論 - 我不知道這就是它的名字。我主要是想知道什麼是「標準」和/或什麼是「良好實踐」,以避免撕裂和競爭條件。 – Will

回答

8

互斥鎖可以保護您免受破綻 - 例如某些ARM實現使用亂序執行,而互斥鎖將包含您的算法正確性可能需要的內存(和編譯器)障礙。

包含互斥鎖更安全,然後找出稍後優化它的方法,如果它顯示爲性能問題。

另請注意,如果您的編譯器是基於GCC的,則可以訪問GCC atomic builtins

+0

感謝您的所有細節。閱讀http://www.usenix.org/event/hotpar11/tech/final_files/Boehm.pdf讓我相信你是對的。 – Will

3

你不需要互斥。 在32位ARM上,單次寫入或讀取是原子操作。 (不管內核的數量如何) 當然,您應該將該變量聲明爲volatile。

+1

對於我上面的簡單情況,我認爲這是有道理的。然而,David Heffernan關於撕裂的評論讓我轉向了http://www.usenix.org/event/hotpar11/tech/final_files/Boehm.pdf。那篇論文讓我對良性數據競賽更加緊張,「易變」可能不是一個完整的解決方案。 – Will

4

如果所有的寫入都是從一個線程完成的(即其他線程只讀),那麼不需要互斥鎖。如果多於一個線程可能正在寫,那麼你這樣做。

1

在32位系統上,讀取和寫入32位變量是原子性的。但是,這取決於你對變量做了什麼。例如。如果你以某種方式操作它(例如添加一個值),那麼這需要讀取,操作和寫入。如果CPU和編譯器不支持此操作的原子操作,那麼您將需要使用一個互斥鎖來保護這個多操作序列。

還有其他無鎖技術可以減少對互斥鎖的需求。

+0

做cpus與非原子「移動」操作存在嗎?我相信每個更新內存位置值的機器指令都是原子的,所有人都應該關心的是,一個線程可以讀取舊值而不是更新的值(在一個線程寫入的情況下,另一個線程只能讀取閱讀,當然) – ShinTakezou

+0

@ShinTakezou - 如果32位變量未對齊,ARM將生成非原子讀/寫。 (即,它將執行4字節的加載而不是字加載以避免未對齊的訪問異常) – Will

+0

ARM還是編譯器?我想這取決於編譯器生成正確的代碼;而且由於編譯器「知道」它確實爲一次寫操作生成4條指令而不是1條指令,所以它可能會設置「障礙」,以便使整個寫入原子化並避免C程序員不必擔心硬件的細節源編譯爲(也許必須有一個選項來禁用這些障礙,但對我來說,他們應該添加默認情況下,如果它是可能的,當然,我想它應該是) – ShinTakezou