2011-12-07 44 views
4

我有一個跨平臺的C++程序,我使用boost庫創建一個異步計時器。
我有一個全局變量:如果兩個線程同時訪問相同的bool變量會發生什麼情況?

bool receivedInput = false; 

一個線程等待和處理輸入

string argStr; 
while (1) 
{ 
    getline(cin, argStr); 
    processArguments(argStr); 
    receivedInput = true; 
} 

另一個線程運行的計時器,其中一個回調函數被每10秒調用。在該回調中,我檢查是否收到了消息

if (receivedInput) 
{ 
    //set up timer to fire again in 10 seconds 
    receivedInput = false; 
} 
else 
    exit(1); 

那麼這是否安全?對於線程2中的讀取,我認爲這並不重要,因爲條件將評估爲真或假。但我不確定如果兩個線程嘗試同時設置receivedInput會發生什麼情況。我也讓我的計時器比我期望接收輸入的時間長3倍,所以我不擔心競賽狀況。

編輯: 爲了解決這個問題,我使用了boost :: unique_lock,當我設置receivedInput和boost :: shared_lock時,當我讀receivedInput。我用here的一個例子

+2

¤如果你想知道它是否安全,那麼它不是。不管技術上是否安全,在線程的情況下,如果你不瞭解它,那麼即使它是完美的開始,它也會在短時間內發現錯誤。因爲它發生的代碼在技術上是不安全的,但實際上是安全的。例如,在技術上,當「輸入」線程處理七行時,「檢查​​」線程可能在「if」處暫停。但在實踐中,這不會發生,但是像Bad Things™*這樣的代碼將會發生。 :-)乾杯&hth。 –

回答

5

這基本上是不安全的。線程1寫入truereceivedInput後,不保證線程2將看到新值。例如,編譯器可能會優化您的代碼,以便在它被用作if條件或將其緩存在寄存器中時對receivedInput的值作出某些假設,因此您不能保證主存儲器在實際讀取時如果條件被評估。此外,編譯器和CPU都可能會改變讀取和寫入的順序以進行優化,例如true可能會在getLine()processArguments()之前寫入receivedInput。另外,依賴於同步的時機是一個非常糟糕的想法,因爲通常你不能保證每個線程在給定的時間間隔內將獲得的CPU時間量,或者它是否將在給定的時間間隔所有。

一個常見的錯誤是認爲製作receivedInputvolatile可能會有所幫助。實際上,volatile保證值實際上被讀取/寫入主存儲器(而不是例如被緩存在寄存器中),並且變量的讀取和寫入相對於彼此排序。但是,它並不保證volatile變量的讀取和寫入相對於其他指令被排序。

您需要內存屏障或適當的同步機制才能按預期工作。

1

你將不得不檢查你的線程標準。假設我們正在討論POSIX線程,這是明確未定義的行爲 - 一個線程可能無法訪問某個對象,而另一個線程正在或可能正在修改它。 任何東西都可能發生。

+2

截至2011年9月,您的線程標準可能是C++標準! –

+0

@SteveJessop我一直在忘記! –

0

如果你的線程使用receivedInput的值來控制獨立的代碼塊,而不是相互同步,有一個簡單的解決方案:

添加「揮發性」 receivedInput之前,所以編譯器不會做優化阻止線程共享receivedInput的值。

+2

我不想-1因爲你是新的,我不想讓你離開,但我不想要「volatile」對多線程傳播有用的誤解。它沒有用,'volatile'與線程無關,也不是同步的一種方法。 – GManNickG

+0

感謝您的評論。是的,我在這裏犯了一個錯誤,兩個線程爲同一個變量賦值。這裏需要同步。但是volatile與多線程無關。 「一般來說,volatile關鍵字旨在防止編譯器對代碼中的任何優化應用,這些代碼假設變量的值無法自行更改(我從wikipedia重新檢查它):) – xiesusu

+1

但請注意,多線程不僅限於對變量禁用優化。 – GManNickG

相關問題