std::call_once
提供: cppreference.com
<tbody>
</tbody>
| ヘッダ <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言語リファレンス
| |