2013-04-04 63 views
6

我有一個簡單的布爾值,我需要以線程安全的方式進行測試和設置。如果一個線程已經工作,我想第二個線程退出。如果我正確理解std::atomic_flag,這應該可以正常工作。但是,我不相信我的理解std::atomic_flag正確:)我似乎無法在網上找到許多簡單的例子,保存這個環形鎖例如:C++ 11 std :: atomic_flag,我正確使用它?

// myclass.cpp 
#using <atomic> 

namespace // anonymous namespace 
{ 
    std::atomic_flag _my_flag = ATOMIC_FLAG_INIT; 
} // ns 

myclass::do_something() 
{ 
    if (!::_my_flag.test_and_set())) 
    { 
     // do my stuff here; handle errors and clear flag when done 
     try 
     { 
      // do my stuff here 
     } 
     catch (...) 
     { 
      // handle exception 
     } 

     ::_my_flag.clear(); // clear my flag, we're done doing stuff 
    } 
    // else, we're already doing something in another thread, let's exit 
} // do_something 

更新:根據下面的建議更新的代碼,形成一個像樣的正確使用std::atomic_flag的模板。謝謝大家!

+0

此代碼無效嗎? – 2013-04-04 19:24:17

+0

@BrendanLong - 我還沒有完全測試它;只是想在我冒險前先確定我是否理解了概念......在我的情況下,「做我的東西」部分將會相當廣泛。雖然我認識到如果需要,我可以輕鬆修改此代碼以使用互斥鎖... – Tom 2013-04-04 19:28:55

+0

在您的問題中沒有問號。 – inf 2013-04-04 20:02:11

回答

5

atomic_flag是一個非常低的水平結構,它並不意味着被廣泛使用。也就是說,我相信你是按照你的意圖使用的,除非在特殊情況下可能會清除旗幟。如果發生除std::exception匹配的異常以外的異常,則標誌不會被清除。

通常RAII應該用於這樣的事情。 'R'通常代表'資源',但我喜歡Jon Kalb的'責任'usage。完成標誌設置後,您有責任清除標誌,因此您應該使用RAII來確保執行責任。如果您在特殊情況下需要做的所有事情都可以這樣完成,那麼try/catch對消失。

if (!std::atomic_flag_test_and_set(&::_my_flag)) 
{ 
    flag_clearer x(&::_my_flag); 

    // do my stuff here 
} 

但是你不需要自己編寫flag_clearer類型。相反,您可以簡單地使用較高級別的構造,例如互斥鎖和鎖定保護程序:

namespace 
{ 
    std::mutex my_flag; 
} 

myclass::do_something() 
{ 
    if (my_flag.try_lock()) 
    { 
     std::lock_guard<std::mutex> x(my_flag, std::adopt_lock); 
     // do my stuff here 
    } 
    // else, we're already doing something in another thread, let's exit 
} 
+1

謝謝bames。 RAII點是很好的。你說得對,我搞錯了我的異常處理。如果爲了簡單起見我仍然想避免使用flag_clearer,我可以用catch(...)替換catch(std :: exception&e)'並且把它稱爲好嗎?順便說一句,我可能會用你的建議代替我的代碼,只是爲了讓它不那麼深奧:)我不需要在我的應用程序中擠掉本節中的每一滴性能。謝謝 – Tom 2013-04-04 20:45:15

+1

@Tom是的,抓住'...'將確保清理代碼運行。 – bames53 2013-04-04 21:08:09

+0

感謝您的跟進,我會用修改後的代碼更新我的文章...然後用您的互斥示例替換我的真實代碼:)再次感謝! – Tom 2013-04-04 21:12:28

1

是的,這將跳過代碼if塊中,如果一些其它線程已經設置標誌,沒有人已清除它。如果沒有其他代碼混淆標誌,這意味着某個線程當前正在執行該塊。

雖然原子標誌是相當低的水平,請考慮使用atomic_bool。此外,由於這是C++,因此您可以使用成員函數來設置和清除。

編輯:

不,atomic_bool不容易做你想做的。與atomic_flag堅持...

+0

皮特,感謝您的確認。我將使用成員函數,我認爲這些函數更具可讀性。再次感謝! – Tom 2013-04-04 20:06:02