c++ call_once 使用详解
std::call_once
-
头文件
#include <mutex>
。 -
函数原型:
cpptemplate<class Callable, class... Args> void call_once(std::once_flag& flag, Callable&& f, Args&&... args);
flag
:标志对象,用于指示 f 是否已调用过。f
:要调用的可调用对象。args
:传递给 f 的参数。
-
作用:保证可调用对象 f 只被执行一次,即使同时从多个线程调用。
-
注意事项:
- 如果在调用 std::call_once 的时刻,flag 指示 f 已经调用过,那么 std::call_once 会立即返回。
- 如果在调用 f 时抛出了异常,那么异常将传播给 std::call_once 的调用方,并且 flag 不会被翻转。
- 如果调用正常返回,那么 flag 被翻转,并保证以同一 flag 对 std::call_once 的其他调用立即返回。
- 如果有多个线程同时在 flag 未翻转时调用 std::call_once,那么这些调用将被组成单独全序,并被依次执行。
示例代码
cpp
#include <cstdio>
#include <mutex>
#include <thread>
std::once_flag flag1, flag2;
void simple_do_once()
{
std::call_once(flag1, []() { printf("only call once\n"); });
}
void may_throw_function(bool do_throw)
{
if (do_throw) {
printf("throw, try again...\n");
throw std::exception();
}
printf("no throw, call once\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);
st1.join();
st2.join();
std::thread t1(do_once, true);
std::thread t2(do_once, false);
std::thread t3(do_once, true);
t1.join();
t2.join();
t3.join();
}