std::call_once

来自cppreference.com
< cpp‎ | thread
定义于头文件 <mutex>
template< class Callable, class... Args >
void call_once( std::once_flag& flag, Callable&& f, Args&&... args );
(C++11 起)

准确执行一次可调用 (Callable) 对象 f ,即使从多个线程调用。

每组接收同一 std::once_flag 对象的 call_once 调用将符合下列要求:

  • 进行函数(在组中作为 f 传递给调用)的准确之一的准确一次执行。为执行选择哪个函数是未指定的。得到选择的函数运行于与它被传递到的 call_once 调用所在线程相同的线程。
  • 在上述被选择函数成功执行,即不通过异常退出之前,组中没有调用会返回。
  • 若被选择函数通过异常退出,则异常被传播给调用方。然后选择并执行另一函数。

目录

[编辑] 参数

flag - 对象,对于它只有一个函数得到执行
f - 要调用的可调用 (Callable) 对象
args... - 传递给函数的参数

[编辑] 返回值

(无)

[编辑] 异常

  • 若任何条件阻止对 call_once 的调用按规定执行,则抛出 std::system_error
  • 任何 f 所抛的异常

[编辑] 注意

可调用 (Callable) 对象的参数被移动或以值复制。若需要传递引用参数给可调用 (Callable) 对象,则必须包装它(例如以 std::refstd::cref )。

(C++17 前)

传递给可调用 (Callable) 对象的参数被完美转发(如同以 std::forward<Callable>(f)std::forward<Args>(args))... ),这异于 thread 构造函数或 std::async可调用 (Callable) 的用法,因为 call_once 不必转移其参数给另一执行线程,从而不必移动或复制。

(C++17 起)

函数局域静态对象的初始化保证仅发生一次,即使在从多个线程调用时,而这可能比使用 std::call_once 的等价代码更为高效。

[编辑] 示例

#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"; // 这会出现多于一次
    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();
}

可能的输出:

Simple example: called once
throw: call_once will retry
throw: call_once will retry
Didn't throw, call_once will not attempt again

[编辑] 参阅

(C++11)
确保 call_once 只调用函数一次的帮助对象
(类) [编辑]
call_onceC 文档