std::call_once
來自 cppreference.com
定義於標頭檔案 <mutex> |
||
template< class Callable, class... Args > void call_once( std::once_flag& flag, Callable&& f, Args&&... args ); |
(C++11 起) | |
即使在多個執行緒中同時呼叫,f這個可呼叫 (Callable) 物件也只會被精確地執行一次。
詳細說明
- 如果,當呼叫
std::call_once
時,flag指示f已被呼叫過,std::call_once
會立即返回(這種對std::call_once
的呼叫被稱為被動 (passive))。
- 否則,
std::call_once
會呼叫INVOKE(std::forward<Callable>(f), std::forward<Args>(args)...)。與std::thread建構函式或std::async不同,引數不會被移動或複製,因為它們不需要轉移到另一個執行執行緒(這種對std::call_once
的呼叫被稱為主動 (active))。
- 如果該呼叫丟擲異常,則該異常會傳播到
std::call_once
的呼叫者,並且flag不會被翻轉,以便再次嘗試呼叫(這種對std::call_once
的呼叫被稱為異常 (exceptional))。 - 如果該呼叫正常返回(這種對
std::call_once
的呼叫被稱為返回 (returning)),則flag會被翻轉,並且所有其他使用相同flag的std::call_once
呼叫都保證是被動 (passive)的。
- 如果該呼叫丟擲異常,則該異常會傳播到
對相同flag的所有主動 (active)呼叫形成一個單一的總順序,該順序由零個或多個異常 (exceptional)呼叫,後跟一個返回 (returning)呼叫組成。每個主動 (active)呼叫的結束與該順序中的下一個主動 (active)呼叫同步。
返回 (returning)呼叫的返回與使用相同flag的所有被動 (passive)呼叫的返回同步:這意味著所有對std::call_once
的併發呼叫都保證能夠觀察到主動 (active)呼叫所產生的任何副作用,而無需額外的同步。
目錄 |
[編輯] 引數
flag | - | 一個物件,其關聯的函式只會執行一次。 |
f | - | 要呼叫的可呼叫 (Callable) 物件。 |
args... | - | 要傳遞給函式的引數。 |
[編輯] 返回值
(無)
[編輯] 異常
- 如果任何條件阻止
std::call_once
按照指定執行,則丟擲std::system_error。 - f丟擲的任何異常。
[編輯] 注意
如果併發呼叫std::call_once
傳遞了不同的函式f,則呼叫哪個f是未指定的。所選函式在其被傳遞到的std::call_once
呼叫所在的執行緒中執行。
函式區域性靜態變數的初始化即使在多執行緒中呼叫時也保證只發生一次,並且可能比使用std::call_once
的等效程式碼更高效。
此函式的 POSIX 等效項是 pthread_once
。
[編輯] 示例
執行此程式碼
#include <iostream> #include <mutex> #include <thread> std::once_flag flag1, flag2; void simple_do_once() { std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; }); } void may_throw_function(bool do_throw) { if (do_throw) { std::cout << "Throw: call_once will retry\n"; // this may appear more than once throw std::exception(); } std::cout << "Did not throw, call_once will not attempt again\n"; // guaranteed once } void do_once(bool do_throw) { try { std::call_once(flag2, may_throw_function, do_throw); } catch (...) {} } int main() { std::thread st1(simple_do_once); std::thread st2(simple_do_once); std::thread st3(simple_do_once); std::thread st4(simple_do_once); st1.join(); st2.join(); st3.join(); st4.join(); std::thread t1(do_once, true); std::thread t2(do_once, true); std::thread t3(do_once, false); std::thread t4(do_once, true); t1.join(); t2.join(); t3.join(); t4.join(); }
可能的輸出
Simple example: called once Throw: call_once will retry Throw: call_once will retry Throw: call_once will retry Did not throw, call_once will not attempt again
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
LWG 2080 | C++11 | 如果f無效,則會丟擲std::invalid_argument, 但f失效的場景未指定 |
移除了此錯誤條件 |
LWG 2442 | C++11 | 引數在呼叫前被複制和/或移動 | 不執行復制/移動 |
[編輯] 參閱
(C++11) |
輔助物件,確保call_once只調用函式一次 (類) |
C 文件,關於call_once
|