public member function
<mutex>

std::call_once

template <class Fn, class... Args>  void call_once (once_flag& flag, Fn&& fn, Args&&... args);
只调用一次函数
调用 fn 并将 args 作为参数传递,除非另一个线程已经使用相同的 flag 执行(或正在执行)一次 call_once 调用。

如果另一个线程正在与同一 flag 主动执行 call_once 调用,则会发生被动执行被动执行 不调用 fn,但直到主动执行本身返回并且所有可见的副作用在此刻同步到具有相同 flag 的所有并发调用为止,才返回。

如果一次主动执行通过抛出异常(该异常会传播到其调用线程)而结束,并且存在被动执行,则会从这些被动执行中选择一个,并将其调用为新的主动执行

请注意,一旦主动执行返回,所有当前的被动执行以及未来(具有相同 flag)对 call_once 的调用都将返回,而不会成为主动执行

主动执行使用 fnargslvaluervalue 引用的decay 副本,并忽略 fn 返回的值。

参数

flag
用于跟踪调用状态的函数对象。
在不同线程中使用相同的对象进行调用,如果并发调用,则只执行一次。
如果 flag 的状态无效,则函数会抛出带有 invalid_argument 错误条件的 system_error 异常。
如果 flag 的状态无效,则该调用会导致未定义行为
call_once 是在头文件 <mutex> 中定义的用于作为此函数参数的特定类型。
fn
函数指针、成员指针,或任何可移动构造的函数对象(即,其类定义了 operator() 的对象,包括闭包function 对象)。
返回值(如果有)将被忽略。
args...
传递给 fn 的参数。它们的类型必须是可移动构造的。
如果 fn成员指针,则第一个参数应为定义了该成员的对象(或其引用或指针)。

返回值



示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// call_once example
#include <iostream>       // std::cout
#include <thread>         // std::thread, std::this_thread::sleep_for
#include <chrono>         // std::chrono::milliseconds
#include <mutex>          // std::call_once, std::once_flag

int winner;
void set_winner (int x) { winner = x; }
std::once_flag winner_flag;

void wait_1000ms (int id) {
  // count to 1000, waiting 1ms between increments:
  for (int i=0; i<1000; ++i)
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  // claim to be the winner (only the first such call is executed):
  std::call_once (winner_flag,set_winner,id);
}

int main ()
{
  std::thread threads[10];
  // spawn 10 threads:
  for (int i=0; i<10; ++i)
    threads[i] = std::thread(wait_1000ms,i+1);

  std::cout << "waiting for the first among 10 threads to count 1000 ms...\n";

  for (auto& th : threads) th.join();
  std::cout << "winner thread: " << winner << '\n';

  return 0;
}

可能的输出(获胜者可能不同)

waiting for the first among 10 threads to count 1000 ms...
winner thread: 2


数据竞争

该函数修改 flag,并访问 fnargs 以创建其 lvaluervalue 引用的decay 副本

异常安全

如果函数本身失败,它会抛出 system_error 异常,并使所有对象处于有效状态(基本保证)。
否则,主动执行提供与对参数执行的操作相同的保证级别。

另见