2016-01-20 40 views
2

假設有一個由主線程控制的布爾標誌(keep_running)。另一個線程無限循環直到該標誌變爲假。應該布爾標誌總是原子?

int main() { 
    bool keep_running(true); 
    std::thread run([](bool &keep_running) 
    { 
     while(keep_running) 
     { 
      // do work 
     } 
    }, std::ref(keep_running)); 

    // do other work 
    keep_running = false; 
    run.join(); 
    return 0; 
} 

該標誌應該是原子嗎?

std::atomic<bool> keep_running 

我想,這可能發生在非原子版本最差的將是標誌被正確的執行

while(keep_running) 

當時間設定。在這種情況下,循環會繼續運行一次(不是嚴格需要的)迭代。但就我而言,這是可以接受的。

上面的代碼可能是錯誤的嗎?

編輯:

我在這個性能方面的原因大多是興趣(和沒有錯誤)。因此,對循環中的標誌使用std :: atomic是否會對性能產生負面影響?

+1

在老版本的C++中,你會使用'volatile' - 沒有它,就有可能從另一個線程看不到從一個線程寫入變量。但是,因爲在C++ 11中有'atomic',你應該使用它來防止相同的問題。 –

+0

當然它應該是原子的。這給你正確的語義。你爲什麼要做其他事情? –

+0

我在想,我在旗幟周圍也不需要記憶障礙,也不需要關心指令重新排序。因此,我認爲我可以擺脫std :: atomic來獲得性能。我試圖澄清,通過編輯問題。但是我沒有意識到變量可能會卡在寄存器中,正如Tsyvarev在他的回答中所指出的那樣。 –

回答

6

這只是C++ 11標準,它禁止(標記爲未定義行爲)併發訪問非原子變量。

所以你需要聲明這個變量原子。

請注意,使用keep_running.load(std::memory_order_relaxed)作爲讀取值,使用keep_running.store(true, std::memory_order_relaxed)作爲寫入值將消除任何額外的性能成本,因此導致的代碼將會像沒有原子的代碼一樣快。


我想,這可能發生在非原子版本最差的將是標誌被正確的時間設置。

可能發生的情況是,在您的線程中,變量將被存儲到寄存器中並且永不會被重新加載(所以線程永遠不會被停止)。如果沒有atomic或其他特殊類型和修飾符,編譯器可以這樣做,而且它確實如此。

+1

我會對此表示贊同,但認爲「可能發生的最糟糕的是變量將被存儲到您的線程中的寄存器中,並且不會被重新加載」是誤導性的。就UB而言,可能發生的最糟糕的事情是什麼。 Te編譯器可以做任何響應它的任何事情,包括程序中任何一點的失敗。請添加一個這樣的記錄,這將是一個很好的答案。 – Vality

+0

這篇文章以關於UB的概念開始,它被標準禁止*。最後,我沒有必要在信息部分重複這一點。但是我已經刪除了「最糟糕的」字樣,所以它只是可能的*壞*情況之一,而不是唯一的情況。 – Tsyvarev

+0

謝謝,這是完美的,我不是說它應該重複,只是它不會讓OP認爲這是唯一可能發生的「最糟糕」似乎+1的不良影響 – Vality