C++11中的std::call_once函数位于<mutex>头文件中。

在多线程编程中,有时某个任务只需要执行一次,此时可以用C++11中的std::call_once函数配合std::once_flag来实现。如果多个线程需要同时调用某个函数,std::call_once可以保证多个线程对该函数只调用一次。也可用在解决线程安全的单例模式。

  1. template<class Callable, class... Args >
  2. void call_once(std::once_flag& flag, Callable&& f, Args&&... args );

std::call_once: Executes the Callable object f exactly once, even if called from several threads.

Each group of call_once invocations that receives the same std::once_flag object will meet the following requirements:

(1). Exactly one execution of exactly one of the functions (passed as f to the invocations in the group) is performed. It is undefined which function will be selected for execution. The selected function runs in the same thread as the call_once invocation it was passed to.

(2). No invocation in the group returns before the above-mentioned execution of the selected function is completed successfully, that is, doesn't exit via an exception.

(3). If the selected function exits via exception, it is propagated to the caller. Another function is then selected and executed.

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

  1. #include "call_once.hpp"
  2. #include <iostream>
  3. #include <thread>
  4. #include <mutex>
  5. #include <chrono>
  6. #include <future>
  7. /*
  8. template< class Callable, class... Args >
  9. void call_once( std::once_flag& flag, Callable&& f, Args&&... args );
  10. Calls fn passing args as arguments, unless another thread has already executed
  11. (or is currently executing) a call to call_once with the same flag.
  12. If another thread is already actively executing a call to call_once with the same flag,
  13. it causes a passive execution: Passive executions do not call fn but do not return until
  14. the active execution itself has returned, and all visible side effects are synchronized at
  15. that point among all concurrent calls to this function with the same flag.
  16. If an active call to call_once ends by throwing an exception (which is propagated
  17. to its calling thread) and passive executions exist, one is selected among these
  18. passive executions, and called to be the new active call instead.
  19. Note that once an active execution has returned, all current passive executions
  20. and future calls to call_once (with the same flag) also return without becoming active executions.
  21. The active execution uses decay copies of the lvalue or rvalue references of fn and args,
  22. ignoring the value returned by fn.
  23. */
  24. namespace call_once_ {
  25. /
  26. // reference: http://en.cppreference.com/w/cpp/thread/call_once
  27. namespace {
  28. std::once_flag flag1, flag2;
  29. void simple_do_once()
  30. {
  31. std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
  32. }
  33. void may_throw_function(bool do_throw)
  34. {
  35. if (do_throw) {
  36. std::cout << "throw: call_once will retry\n"; // this may appear more than once
  37. throw std::exception();
  38. }
  39. std::cout << "Didn't throw, call_once will not attempt again\n"; // guaranteed once
  40. }
  41. void do_once(bool do_throw)
  42. {
  43. try {
  44. std::call_once(flag2, may_throw_function, do_throw);
  45. }
  46. catch (...) {
  47. }
  48. }
  49. }
  50. int test_call_once_1()
  51. {
  52. std::thread st1(simple_do_once);
  53. std::thread st2(simple_do_once);
  54. std::thread st3(simple_do_once);
  55. std::thread st4(simple_do_once);
  56. st1.join();
  57. st2.join();
  58. st3.join();
  59. st4.join();
  60. /*std::thread t1(do_once, true);
  61. std::thread t2(do_once, true);
  62. std::thread t3(do_once, false);
  63. std::thread t4(do_once, true);
  64. t1.join();
  65. t2.join();
  66. t3.join();
  67. t4.join();*/
  68. return 0;
  69. }
  70. ///
  71. // reference: http://www.cplusplus.com/reference/mutex/call_once/
  72. namespace {
  73. int winner;
  74. void set_winner(int x) { winner = x; }
  75. std::once_flag winner_flag;
  76. void wait_1000ms(int id) {
  77. // count to 1000, waiting 1ms between increments:
  78. for (int i = 0; i<1000; ++i)
  79. std::this_thread::sleep_for(std::chrono::milliseconds(1));
  80. // claim to be the winner (only the first such call is executed):
  81. std::call_once(winner_flag, set_winner, id);
  82. }
  83. }
  84. int test_call_once_2()
  85. {
  86. std::thread threads[10];
  87. // spawn 10 threads:
  88. for (int i = 0; i<10; ++i)
  89. threads[i] = std::thread(wait_1000ms, i + 1);
  90. std::cout << "waiting for the first among 10 threads to count 1000 ms...\n";
  91. for (auto& th : threads) th.join();
  92. std::cout << "winner thread: " << winner << '\n';
  93. return 0;
  94. }
  95. // reference: http://www.modernescpp.com/index.php/thread-safe-initialization-of-a-singleton
  96. namespace {
  97. /*constexpr*/const auto tenMill = 10000;
  98. class MySingleton{
  99. public:
  100. static MySingleton& getInstance(){
  101. std::call_once(initInstanceFlag, &MySingleton::initSingleton);
  102. // volatile int dummy{};
  103. return *instance;
  104. }
  105. private:
  106. MySingleton() = default;
  107. ~MySingleton() = default;
  108. MySingleton(const MySingleton&) = delete;
  109. MySingleton& operator=(const MySingleton&) = delete;
  110. static MySingleton* instance;
  111. static std::once_flag initInstanceFlag;
  112. static void initSingleton(){
  113. instance = new MySingleton;
  114. }
  115. };
  116. MySingleton* MySingleton::instance = nullptr;
  117. std::once_flag MySingleton::initInstanceFlag;
  118. std::chrono::duration<double> getTime(){
  119. auto begin = std::chrono::system_clock::now();
  120. for (size_t i = 0; i <= tenMill; ++i){
  121. MySingleton::getInstance();
  122. }
  123. return std::chrono::system_clock::now() - begin;
  124. };
  125. }
  126. int test_call_once_3()
  127. {
  128. auto fut1 = std::async(std::launch::async, getTime);
  129. auto fut2 = std::async(std::launch::async, getTime);
  130. auto fut3 = std::async(std::launch::async, getTime);
  131. auto fut4 = std::async(std::launch::async, getTime);
  132. auto total = fut1.get() + fut2.get() + fut3.get() + fut4.get();
  133. std::cout << total.count() << std::endl;
  134. return 0;
  135. }
  136. } // namespace call_once_

GitHub: https://github.com/fengbingchun/Messy_Test

转载自:https://blog.csdn.net/fengbingchun/article/details/78681323

Multi-thread--C++11多线程中std::call_once的使用相关推荐

  1. C++11多线程中std::call_once的使用

    C++11中的std::call_once函数位于<mutex>头文件中. 在多线程编程中,有时某个任务只需要执行一次,此时可以用C++11中的std::call_once函数配合std: ...

  2. C++11 多线程(std::thread)详解

    注:此教程以 Visual Studio 2019 Version 16.10.3 (MSVC 19.29.30038.1) 为标准,大多数内容参照cplusplus.com里的解释 此文章允许转载, ...

  3. C++11多线程之 std::packaged_task

    简介 先给出官网的一个地址:http://www.cplusplus.com/reference/future/packaged_task/?kw=packaged_task 个人认为,相当于一个装饰 ...

  4. 别翻了,成员变量和局部变量在多线程中的使用,看这篇就够了

    一. 成员变量和局部变量的区别 在类中的位置不同 成员变量:在类中方法外面 局部变量:在方法或者代码块中,或者方法的声明上(即在参数列表中) 在内存中的位置不同 成员变量:在堆中(方法区中静态区),成 ...

  5. 【多线程】C++11进行多线程开发 (std::thread)

    文章目录 创建线程 std::thread 类 使用join() 使用 detach() 警惕作用域 线程不能复制 给线程传参 传递指针 传递引用 以类成员函数为线程函数 以容器存放线程对象 互斥量 ...

  6. C++11中std::condition_variable的使用

    <condition_variable>是C++标准程序库中的一个头文件,定义了C++11标准中的一些用于并发编程时表示条件变量的类与方法等. 条件变量是并发程序设计中的一种控制结构.多个 ...

  7. C++11并发之std::thread

    C++11并发之std::thread 知识链接: C++11 并发之std::mutex C++11 并发之std::atomic 本文概要: 1.成员类型和成员函数. 2.std::thread ...

  8. Multi-thread--C++11中std::condition_variable的使用

    <condition_variable>是C++标准程序库中的一个头文件,定义了C++11标准中的一些用于并发编程时表示条件变量的类与方法等. 条件变量是并发程序设计中的一种控制结构.多个 ...

  9. [C++] - C++11 多线程 - Thread

    转载整理自:https://github.com/forhappy/Cplusplus-Concurrency-In-Practice/tree/master/zh/chapter3-Thread 1 ...

最新文章

  1. centos7输入shell找不到命令_反弹shell原理与实现
  2. Git 中的对象模型和文件的详细视图 —— Git 学习笔记 13
  3. 机器人码垛手持式编程_三分钟告诉你企业为什么要使用全自动码垛机械手!
  4. Flink 1.9 写入HDFS报错 UnsupportedFileSystemSchemeException:hdfs
  5. 十大经典排序算法(动图演示)(转)
  6. GBDT的回归、二分类以及多分类教程
  7. 数据比赛大杀器----模型融合(stackingblending)(转载)
  8. pad点餐系统 内存管理的一点总结
  9. python房价预测_Python实战:使用线性回归预测房价
  10. 深入理解HTTP消息头
  11. HDU2177——取(2堆)石子游戏(威佐夫博弈)
  12. c语言汉字utf8,C语言汉字gbk转utf-8
  13. Linux 冗余网络切换时间,linux下实现双网冗余
  14. 微信升级外链管理规范,「砍一刀帮我加速」要被禁止了
  15. 武汉大学计算机学院周维,周维勋
  16. python使用turtle库、绘制一个八边形_【Python】turtle八边形绘制
  17. 陈学贤华南理工大学计算机专业,张见威 - 华南理工大学 - 计算机科学与工程学院...
  18. NET 3行代码实现文字转语音功能
  19. 全球行政区划数据库 地理数据库
  20. RPM打包之spec示例

热门文章

  1. Ngnix安装的几种常用方式
  2. Spring JSF集成
  3. 分布式面试 - 为什么要进行系统拆分?
  4. java 课后习题 键入日期输入星期几
  5. C#LeetCode刷题之#706-设计哈希映射(Design HashMap)
  6. 机器学习相关的一些术语
  7. 如何构建一个简单的语音识别应用程序
  8. Python3 装饰器解析
  9. python爬京东(带GUI)
  10. Ubuntu软件安装