定义于头文件
class once_flag; (C++11 起)
类 std::once_flag 是 std::call_once 的辅助类。
传递给多个 std::call_once 调用的 std::once_flag 对象允许那些调用彼此协调,从而只令调用之一实际运行完成。
std::once_flag 既不可复制亦不可移动。
构造 once_flag 对象。设置内部状态为指示尚未调用函数。
参数 (无)
- template< class Callable, class... Args >
- void call_once( std::once_flag& flag, Callable&& f, Args&&... args ); (C++11 起)
准确执行一次可调用 (Callable) 对象 f ,即使同时从多个线程调用。
细节为:
call_once 的时刻, flag 指示已经调用了 f ,则 call_once 立即返回(称这种对 call_once 的调用为消极)。call_once 以参数 std::forwardcall_once 的调用为积极)。call_once 的调用方,并且不翻转 flag ,以令其他调用将得到尝试(这种对 call_once 的调用被称为异常)。call_once 的调用被称为返回),则翻转 flag ,并保证以同一 flag 对 call_once 的其他调用为消极。同一 flag 上的所有积极调用组成单独全序,它们由零或多个异常调用后随一个返回调用组成。该顺序中,每个积极调用的结尾同步于下个积极调用。
从返回调用的返回同步于同一 flag 上的所有消极调用:这表示保证所有对 call_once 的同时调用都观察到积极调用所做的任何副效应,而无需额外同步。
| flag | - | 对象,对于它只有一个函数得到执行 |
| f | - | 要调用的可调用 (Callable) 对象 |
| args... | - | 传递给函数的参数 |
(无)
call_once 的调用按规定执行,则抛出 std::system_errorf 所抛的异常若对 call_once 的同时调用传递不同的 f ,则调用哪个 f 是未指定的。被选择函数运行于与传递它的 call_once 的调用相同的线程。
即使在从多个线程调用时,也保证函数局域静态对象的初始化仅出现一次,这可能比使用 std::call_once 的等价代码更为高效。
此函数的 POSIX 类似物是 pthread_once 。
- #include <iostream>
- #include <thread>
- #include <mutex>
-
- //确保 call_once 只调用函数一次的帮助对象
- 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"; // 这会出现多于一次
- throw std::exception();
- }
- std::cout << "Didn't throw, call_once will not attempt again\n"; // 保证一次
- }
-
- 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();
- }
