在C中我有一個指針,聲明爲volatile並初始化爲null。一個線程讀取和另一個寫入volatile變量 - 線程安全?
void* volatile pvoid;
線程1偶爾會讀取指針值來檢查它是否爲非null。線程1不會設置指針的值。 線程2將只設置一次指針的值。
我相信我可以脫身而不使用互斥或條件變量。
是否有任何原因線程1會讀取損壞的值或線程2會寫入損壞的值?
在C中我有一個指針,聲明爲volatile並初始化爲null。一個線程讀取和另一個寫入volatile變量 - 線程安全?
void* volatile pvoid;
線程1偶爾會讀取指針值來檢查它是否爲非null。線程1不會設置指針的值。 線程2將只設置一次指針的值。
我相信我可以脫身而不使用互斥或條件變量。
是否有任何原因線程1會讀取損壞的值或線程2會寫入損壞的值?
如果該值適合單個寄存器(如內存對齊的指針),這是安全的。在其他情況下,可能需要多條指令讀取或寫入該值,讀取線程可能會損壞數據。如果您不確定讀取和寫入操作在所有使用情況下都會採用單個指令,請使用原子讀取和寫入操作。
不幸的是,你不能可移植性做出什麼純C.
GCC是原子的任何假設,但確實提供了一些原子的內置函數,需要使用你許多架構的正確指令的照顧。有關更多信息,請參閱Chapter 5.47 of the GCC manual。
好吧,這看起來很好..唯一的問題將發生在這種情況下 讓線程A是你的檢查線程和B修改一個.. 事情是檢查的平等不是原子在技術上首先值應該是複製到寄存器然後檢查然後恢復。讓我們假設線程A已經複製到寄存器,現在B決定改變這個值,現在你的變量的值改變了。所以當控制回到A時,即使它根據線程被調用的時間,它也會說它不是null。這似乎在這個程序無害,但可能會導致問題..
使用互斥體..簡單enuf ..和u可以肯定你沒有同步錯誤!
無論您是否將其加載到寄存器中,您都會遇到它在您查看後可能會更改的情況。 – progrmr 2010-06-19 18:23:48
爲了使線程安全,您必須對變量進行原子讀取/寫入操作,它在所有時序情況下都是不穩定的。在Win32下有互鎖函數,在Linux下,如果你不想使用重量級互斥體和條件變量,你可以使用build it yourself with assembly。
如果您不是針對GPL,那麼http://www.threadingbuildingblocks.org及其atomic<>
模板看起來很有前途。 lib是跨平臺的。
取決於您的編譯器,體系結構和操作系統。 POSIX(因爲這個問題被標記爲pthreads我假設我們不是在談論Windows或其他線程模型),並且C沒有給出足夠的約束來解決這個問題。
安全的假設當然是保護與互斥體訪問指針。然而根據你對問題的描述,我想知道pthread_once是不是一個更好的方法。當然,在問題中沒有足夠的信息來表達某種方式。
好的,所以在某些平臺上有可能無法很好地處理指針地址。但是你的回答表明,檢查一個布爾標誌是否從0變爲非零是可以的,因爲即使讀取值被破壞,它仍然可能返回非零值,並且只有在寫入發生之後。如果損壞的值恰好爲零,那麼檢查線程會在下一次讀取時獲取它。是嗎? – 2010-06-19 18:30:48
由於讀取中斷了寫入,並且一個或另一個會佔用多於一條指令,所以會發生損壞。如果你的標誌是單個字節,那麼我不能想到它可能被中斷的情況,但是不能保證標誌和指針被串行寫入。如果你有原子操作,它們比標誌更好。 – drawnonward 2010-06-19 18:53:56