2014-10-30 408 views
5

所以我開始熟悉C++ 11 <atomic>類型。在過去,當我有一個原子標記時,我通常會在訪問它之前鎖定一個互斥鎖。一個常見的需求是檢查標誌是否爲false,如果是,自動將其設置爲true然後執行某些操作。所以基本上這將是這樣來完成,其中flag是一個簡單的boolstd :: atomic原理的基本用法<T>

{ 
    std::lock_guard<std::mutex> lock(my_mutex); 
    if (!flag) 
    { 
     flag = true; 
     // do something; 
    } 
} 

所以,現在我想弄清楚是怎麼一回事可以<atomic>來完成。 docs表示原子類型的賦值運算符和operator T是原子操作。但是,如果我改變flagstd::atomic<bool>,我想我不能簡單說:

if (!flag) 
{ 
    flag = true; 
    // do something 
} 

...因爲即使表達(!flag)是原子,並分配flag = true是原子的,沒有什麼可以阻止另一個線程從修改這兩條語句之間的標誌。

所以,如果我理解正確的話在這裏,唯一的正確用法 - 在所有 - 用原子類型,其中有條件的結果可以修改原子變量條件句,是使用比較和交換操作?我對麼?

所以,我不得不說:

bool expected = false; 
if (flag.compare_exchange_weak(expected, true)) 
{ 
    // do something 
} 

我是在我的理解正確嗎?

+2

['std :: atomic_flag'](http://en.cppreference.com/w/cpp/atomic/atomic_flag)存在於您正在描述的用例中,而且更確切地說它是鎖定的,在所有平臺上免費。你可以使用'test_and_set'方法,它是原子的。你也可以使用'std :: atomic '並在其上執行一個'fetch_add',它是原子的,在增量完成時會給你以前的值(在大多數體系結構中這通常比CAS更快,儘管我想不會比'std :: atomic_flag'更快,在這種情況下這將是我的首選)。 – Cameron 2014-10-30 15:31:19

+0

對 - 但似乎沒有辦法簡單地原子地「檢查」原子標記的值(沒有設置它) - 或者是否存在?文檔沒有定義「運算符布爾」或任何可以啓用表達式「if(flag)」的內容。我意識到我沒有在我的問題中指定這個要求 - 我只是想知道。說到......爲什麼*不是*有辦法簡單地檢查原子標誌而不設置它? – Siler 2014-10-30 15:54:09

+0

這是正確的,你必須設置它才能測試它(這與你當前編寫的示例代碼相同,只是它是原子的)。如果你需要獨立測試它,我建議使用'fetch_add'方法或'compare_exchange_strong'(它更清晰,並且[與x86上的'fetch_add'('lock xadd')一樣快](http:// www.agner.org/optimize/instruction_tables.pdf))。 – Cameron 2014-10-30 15:55:35

回答

3

如果你有多個線程運行相同的代碼,需要做這個翻轉,是的 - 你需要使用compare_exchange_weak()compare_exchange_strong()正是你建議(可能更喜歡強)的原因。

但是,並不是說這是只有正確使用條件與原子。如果我有,比方說,一個永遠只能讀取的原子線程和一個寫入到它,這是完全合理的使用這些簡單的方法......例如:

std::atomic<bool> done{false}; 

// thread 1 
while (!done) { 
    .... 
} 

// thread 2 
stop() { done = true; } 

沒有理由爲我做一那裏有done.compare_exchange_strong(expected, true)。這太過分了。這實際上是基於個案的。

+0

從OP的代碼中可以明顯看出'compare_exchange_ {weak,strong}'在這種情況下是合適的。這個問題確定了「僅限」一詞的條件,即比較結果將用於決定是否進行分配。儘管如此,對於更廣泛的用例來說,還是很好的徹底答案。 – 2014-10-30 15:28:57

1

是的。

這就是說,你可能更喜歡compare_exchange_strong這個,除非你在一個緊密的循環。它可能會導致性能下降,但保證會給您預期的結果(其中compare_exchange_weak不是)。

0

明顯的注意:鎖定語義與原子檢查完全不同,因爲在這種情況下,另一個線程會等待,直到鎖定釋放,並且在獲取鎖定後始終執行其操作。因此,嚴格來說,兩個代碼示例並不等同。

相關問題