c++ std::call_once

23 篇文章 1 订阅

在多线程中,有一种场景是某个任务只需要执行一次,可以用C++11中的std::call_once函数配合std::once_flag来实现。多个线程同时调用某个函数,std::call_once可以保证多个线程对该函数只调用一 次。

函数定义于头文件<mutex>。函数原型

template<classCallable,class... Args>

voidcall_once(std::once_flag&flag,Callable&&f,Args&&...args);

准确执行一次可调用 (Callable) 对象 f ,即使同时从多个线程调用。若在调用 call_once 的时刻, flag 指示已经调用了 f ,则 call_once 立即返回(称这种对 call_once 的调用为消极)。否则, call_once 以参数 std::forward<Args>(args)... 调用 std::forward<Callable>(f) (如同用std::invoke)。不同于 std::thread构造函数或 std::async,不移动或复制参数,因为不需要转移它们到另一执行线程(称这种对 call_once 的调用为积极)。若该调用抛异常,则传播异常给 call_once 的调用方,并且不翻转 flag ,以令其他调用将得到尝试(称这种对 call_once 的调用为异常)。

若该调用正常返回(称这种对 call_once 的调用为返回),则翻转 flag ,并保证以同一 flag 对 call_once 的其他调用为消极。同一 flag 上的所有积极调用组成单独全序,它们由零或多个异常调用后随一个返回调用组成。该顺序中,每个积极调用的结尾同步于下个积极调用。

从返回调用的返回同步于同一 flag 上的所有消极调用:这表示保证所有对 call_once 的同时调用都观察到积极调用所做的任何副效应,而无需额外同步。

若对 call_once 的同时调用传递不同的 f ,则调用哪个 f 是未指定的。被选择函数运行于与传递它的 call_once 的调用相同的线程。即使在从多个线程调用时,也保证函数局域静态对象的初始化仅出现一次,这可能比使用 std::call_once 的等价代码更为高效。此函数的 POSIX 类似函数是 pthread_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(...){

    }

}

//对比普通函数

void PrintNun()

{

    std::cout << "Hello World\n";

}

int main()

{

    //普通函数

    std::thread st11(PrintNun);

    std::thread st21(PrintNun);

    std::thread st31(PrintNun);

    std::thread st41(PrintNun);

    st11.join();

    st21.join();

    st31.join();

    st41.join();

    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();

 

}

输出结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值