• C++11 多线程支持-单次调用


    定义于头文件 

    确保 call_once 只调用函数一次的帮助对象

    class once_flag;                 (C++11 起) 

    std::once_flag 是 std::call_once 的辅助类。

    传递给多个 std::call_once 调用的 std::once_flag 对象允许那些调用彼此协调,从而只令调用之一实际运行完成。

    std::once_flag 既不可复制亦不可移动。

    构造 once_flag 对象。设置内部状态为指示尚未调用函数。

    参数                (无)

    仅调用函数一次,即使从多个线程调用

    1. template< class Callable, class... Args >
    2. 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​::​forward(args)... 调用 ​std​::​forward(f) (如同用 std::invoke )。不同于 std::thread 构造函数或 std::async ,不移动或复制参数,因为不需要转移它们到另一执行线程(称这种对 call_once 的调用为积极)。
    • 若该调用抛异常,则传播异常给 call_once 的调用方,并且不翻转 flag ,以令其他调用将得到尝试(这种对 call_once 的调用被称为异常)。
    • 若该调用正常返回(这种对 call_once 的调用被称为返回),则翻转 flag ,并保证以同一 flagcall_once 的其他调用为消极

    同一 flag 上的所有积极调用组成单独全序,它们由零或多个异常调用后随一个返回调用组成。该顺序中,每个积极调用的结尾同步于下个积极调用。

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

    参数

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

    返回值

    (无)

    异常

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

    注解

    若对 call_once 的同时调用传递不同的 f ,则调用哪个 f 是未指定的。被选择函数运行于与传递它的 call_once 的调用相同的线程。

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

    此函数的 POSIX 类似物是 pthread_once

    调用示例

    1. #include <iostream>
    2. #include <thread>
    3. #include <mutex>
    4. //确保 call_once 只调用函数一次的帮助对象
    5. std::once_flag flag1, flag2;
    6. void simple_do_once()
    7. {
    8. // 仅调用函数一次,即使从多个线程调用
    9. std::call_once(flag1, []()
    10. {
    11. std::cout << "Simple example: called once\n";
    12. });
    13. }
    14. void may_throw_function(bool do_throw)
    15. {
    16. if (do_throw)
    17. {
    18. std::cout << "throw: call_once will retry\n"; // 这会出现多于一次
    19. throw std::exception();
    20. }
    21. std::cout << "Didn't throw, call_once will not attempt again\n"; // 保证一次
    22. }
    23. void do_once(bool do_throw)
    24. {
    25. try
    26. {
    27. std::call_once(flag2, may_throw_function, do_throw);
    28. }
    29. catch (...)
    30. {
    31. }
    32. }
    33. int main()
    34. {
    35. std::thread st1(simple_do_once);
    36. std::thread st2(simple_do_once);
    37. std::thread st3(simple_do_once);
    38. std::thread st4(simple_do_once);
    39. st1.join();
    40. st2.join();
    41. st3.join();
    42. st4.join();
    43. std::thread t1(do_once, true);
    44. std::thread t2(do_once, true);
    45. std::thread t3(do_once, false);
    46. std::thread t4(do_once, true);
    47. t1.join();
    48. t2.join();
    49. t3.join();
    50. t4.join();
    51. }

     

    可能的输出

     

  • 相关阅读:
    在nodejs中实现实时通信的几种方式
    【Python】国内生产总值分析预测
    如何理解TCP/IP协议?
    HC32L110(五) Ubuntu20.04 VSCode的Debug环境配置
    Hugging News #0616: 有几项非常重要的合作快来围观、最新中文演讲视频回放发布!
    763. Partition Labels
    30岁被公司裁员,有人从此一蹶不振,而我逆风翻盘,重获新生~
    ciscn_2019_s_9
    Rockchip Linux SDK软件包的解压
    mysql源码编译安装
  • 原文地址:https://blog.csdn.net/qq_40788199/article/details/126435712