2010-06-19 227 views
4

在C中我有一個指針,聲明爲volatile並初始化爲null。一個線程讀取和另一個寫入volatile變量 - 線程安全?

void* volatile pvoid; 

線程1偶爾會讀取指針值來檢查它是否爲非null。線程1不會設置指針的值。 線程2將只設置一次指針的值。

我相信我可以脫身而不使用互斥或​​條件變量。
是否有任何原因線程1會讀取損壞的值或線程2會寫入損壞的值?

回答

2

如果該值適合單個寄存器(如內存對齊的指針),這是安全的。在其他情況下,可能需要多條指令讀取或寫入該值,讀取線程可能會損壞數據。如果您不確定讀取和寫入操作在所有使用情況下都會採用單個指令,請使用原子讀取和寫入操作。

+0

好的,所以在某些平臺上有可能無法很好地處理指針地址。但是你的回答表明,檢查一個布爾標誌是否從0變爲非零是可以的,因爲即使讀取值被破壞,它仍然可能返回非零值,並且只有在寫入發生之後。如果損壞的值恰好爲零,那麼檢查線程會在下一次讀取時獲取它。是嗎? – 2010-06-19 18:30:48

+0

由於讀取中斷了寫入,並且一個或另一個會佔用多於一條指令,所以會發生損壞。如果你的標誌是單個字節,那麼我不能想到它可能被中斷的情況,但是不能保證標誌和指針被串行寫入。如果你有原子操作,它們比標誌更好。 – drawnonward 2010-06-19 18:53:56

-2

在大多數平臺上,指針值可以在單個指令中讀取/寫入,可以設置,也可以不設置。它不能在中間中斷,並且包含損壞的值。在這種平臺上不需要互斥鎖。

+3

在所有平臺上都不是這樣 – jdehaan 2010-06-19 18:12:56

+0

這不適用於哪種平臺? 16位整數的CPU? – progrmr 2010-06-19 18:22:13

+0

具有非32位存儲器訪問的系統,確實存在,特別是在DSP-land中。此外,必須對齊32位內存訪問,並且訪問的值未對齊。 – 2010-06-19 18:46:58

0

不幸的是,你不能可移植性做出什麼純C.

GCC是原子的任何假設,但確實提供了一些原子的內置函數,需要使用你許多架構的正確指令的照顧。有關更多信息,請參閱Chapter 5.47 of the GCC manual

0

好吧,這看起來很好..唯一的問題將發生在這種情況下 讓線程A是你的檢查線程和B修改一個.. 事情是檢查的平等不是原子在技術上首先值應該是複製到寄存器然後檢查然後恢復。讓我們假設線程A已經複製到寄存器,現在B決定改變這個值,現在你的變量的值改變了。所以當控制回到A時,即使它根據線程被調用的時間,它也會說它不是null。這似乎在這個程序無害,但可能會導致問題..

使用互斥體..簡單enuf ..和u可以肯定你沒有同步錯誤!

+0

無論您是否將其加載到寄存器中,您都會遇到它在您查看後可能會更改的情況。 – progrmr 2010-06-19 18:23:48

3

爲了使線程安全,您必須對變量進行原子讀取/寫入操作,它在所有時序情況下都是不穩定的。在Win32下有互鎖函數,在Linux下,如果你不想使用重量級互斥體和條件變量,你可以使用build it yourself with assembly

如果您不是針對GPL,那麼http://www.threadingbuildingblocks.org及其atomic<>模板看起來很有前途。 lib是跨平臺的。

+1

我有點困惑。變量是多麼易變,確保它首先是線程安全的? – Laz 2010-06-19 18:20:44

+0

揮發性涉及的內存屏障對於原子機制起作用是必不可少的,但只是整體的一部分。 – jdehaan 2010-06-19 18:25:08

0

取決於您的編譯器,體系結構和操作系統。 POSIX(因爲這個問題被標記爲pthreads我假設我們不是在談論Windows或其他線程模型),並且C沒有給出足夠的約束來解決這個問題。

安全的假設當然是保護與互斥體訪問指針。然而根據你對問題的描述,我想知道pthread_once是不是一個更好的方法。當然,在問題中沒有足夠的信息來表達某種方式。

相關問題