3

如果我有以下的僞代碼:在產生訪問它的子線程之前,是否應該訪問由父線程鎖定的共享資源?

sharedVariable = somevalue;
CreateThread(threadWhichUsesSharedVariable);

是理論上可能的多核CPU在threadWhichUsesSharedVariable()父線程寫入之前讀取sharedVariable的值執行代碼?有關連的競爭條件的可能性極小充分的理論迴避,應該代碼看起來像這個:

sharedVariableMutex.lock();
sharedVariable = somevalue;
sharedVariableMutex.unlock();
CreateThread(threadWhichUsesSharedVariable);

基本上我想知道的產卵線程在那個時候顯式線性化CPU,並且保證這樣做。

我知道線程創建的開銷可能需要足夠的時間,這在實踐中永遠不會起作用,但我的完美主義者害怕理論上的競爭條件。在極端情況下,某些線程或內核可能會嚴重滯後,其他線程可能會快速高效地運行,但我可以想象,除非出現鎖定,否則執行順序(或內存訪問)可能會反向。

+0

我的問題涉及到像C++這樣的語言,其中您接近機器級別,並使用簡單的InterlockedExchange循環實現「鎖定」。 我擔心聲明變量「volatile」不足以確保同步。 「原子」和「同步」之間沒有區別嗎?原子操作不能被分割 - 如果一個變量被聲明爲volatile,編譯器不會重新對它進行排序 - 但是CPU不能重新排序它們?特別是當被不同內核訪問時? – Deadcode 2010-02-11 08:38:09

+0

附加說明:在我的示例中,「sharedVariable = somevalue」用於將數據傳遞給threadWhichUsesSharedVariable。 threadWhichUsesSharedVariable在由父線程分配後才訪問「sharedVariable」,這一點非常重要。 – Deadcode 2010-02-11 08:50:00

+1

如果重新排序對程序不可見 ,CPU只能重新排序訪問,所以CPU重新排序不應該成爲問題。設計多核系統的複雜性大部分在於確保程序從不會看到與單核系統有所不同的行爲。 – 2010-02-11 16:55:35

回答

2

我會說你的僞代碼在任何正確運行的多處理器系統上都是安全的。在sharedVariable接收到正確的值 之前,C++編譯器無法生成對 CreateThread()的調用,除非它能證明自己這樣做是安全的。您保證 您的單線程代碼執行等效於完全 非重新排序的線性執行路徑。在變量分配之前「創建時間」線程創建的任何系統都被嚴重破壞。

我不認爲聲明sharedVariable爲揮發性,在這種情況下 有用。

1

給出您的示例,如果您使用的是Java,那麼答案將是「否」。在Java中,分配操作完成之前,線程不可能產生並讀取您的值。 在其他一些語言中,這可能是一個不同的故事。

「變量的多個線程之間共享(例如,對象的實例變量)具有由對所有數據類型的Java語言規範保證除了多頭原子分配和雙打...如果一個方法僅由一個單一的可變訪問或賦值,不需要爲了線程安全而進行同步,也不需要爲了性能而做到這一點。「 reference

如果您doublelong聲明volatile,那麼你也保證轉讓是一個原子操作。

更新: 您的示例將在C++中工作,就像它在Java中工作一樣。從理論上講,線程產生將不會在分配之前開始或完成,即使是無序執行。

請注意,您的示例非常具體,在任何其他情況下,建議您確保共享資源得到正確保護。新的C++標準出現了很多原子的東西,所以你可以將你的變量聲明爲原子,並且賦值操作對於所有線程都是可見的,而不需要鎖定。 CAS(比較和設定)是您的下一個最佳選擇。

+0

感謝您的回答,但我的確在詢問C++(或任何使您接近機器級別的語言),並應如此說。我會添加一條評論來澄清我的問題。 – Deadcode 2010-02-11 08:34:54

+0

謝謝Lirik和Per,你的回答都很有幫助。 – Deadcode 2010-02-13 13:51:08