std::call_once
提供: cppreference.com
ヘッダ <mutex> で定義
|
||
template< class Callable, class... Args > void call_once( std::once_flag& flag, Callable&& f, Args&&... args ); |
(C++11以上) | |
複数のスレッドから並行的に呼ばれた場合でも、 Callable なオブジェクト f
をちょうど一度だけ実行します。
詳細は以下の通りです。
-
call_once
が呼ばれた時点で、f
がすでに呼ばれたことをflag
が示す場合、call_once
はすぐに戻ります (このようなcall_once
の呼び出しは passive と言います)。
- そうでなければ、
call_once
は引数 std::forward<Args>(args)... を用いて std::forward<Callable>(f) を呼びます。 std::thread のコンストラクタや std::async と異なり、引数は別のスレッドに転送される必要はないため、ムーブもコピーもされません (このようなcall_once
の呼び出しは active と言います)。
- その呼び出しが例外を投げた場合、それは
call_once
の呼び出し元に伝搬され、別の呼び出しを試みられるようにフラグの反転は行われません (このようなcall_once
の呼び出しは exceptional と言います)。 - その呼び出しが正常に戻った場合 (このような
call_once
の呼び出しは returning と言います)、フラグは反転され、同じフラグを使用した他のすべてのcall_once
の呼び出しは passive となることが保証されます。
- その呼び出しが例外を投げた場合、それは
同じ flag
に対するすべての active な呼び出しは、0回以上の exceptional な呼び出しに続く1回の returning な呼び出しから構成される単一の全順序を形成します。 その順序に��いて、それぞれの active な呼び出しの終わりは、次の active な呼び出しに対して同期します。
returning な呼び出しからの戻りは、同じ flag
に対するすべての passive な呼び出しからの戻りに対して同期します。 これは、すべての並行的な call_once
の呼び出しが、 active な呼び出しによってなされたあらゆる副作用を、追加の同期なしに観測することが保証されることを意味します。
目次 |
[編集] 引数
flag | - | ちょうど一度だけ関数を実行するためのオブジェクト |
f | - | 実行する Callable なオブジェクト |
args... | - | 関数に渡す引数 |
[編集] 戻り値
(なし)
[編集] 例外
- 何らかの状況により
call_once
の呼び出しが指定された内容を実行することが妨げられる場合、 std::system_error。 -
f
によって投げられるあらゆる例外。
[編集] ノート
call_once
の並行的な呼び出しに異なる f
を渡した場合、どの f
が呼ばれるかは未規定です。 選択された関数は、それが渡された call_once
の呼び出しと同じスレッドで実行されます。
関数ローカルな static 変数の初期化は、複数のスレッドから呼ばれた場合でも一度だけ行われることが保証されており、 std::call_once
を使用した同等なコードよりも効率が良い場合があります。
この関数のPOSIX版は pthread_once です。
[編集] 例
Run this code
#include <iostream> #include <thread> #include <mutex> 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"; // これは2回以上表示されるかもしれません。 throw std::exception(); } std::cout << "Didn't throw, call_once will not attempt again\n"; // 1回だけが保証されます。 } 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 Didn't throw, call_once will not attempt again
[編集] 欠陥報告
以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。
DR | 適用先 | 発行時の動作 | 正しい動作 |
---|---|---|---|
LWG 2442 | C++11 | the arguments are copied and/or moved before invocation | no copying/moving is performed |
[編集] 関連項目
(C++11) |
call_once が一度だけ関数を呼び出すことを保証するためのヘルパーオブジェクト (クラス) |
call_once の C言語リファレンス
|