不要用std::thread写裸线程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/daan_112211/article/details/19088605

我们先看一段代码:

  1. #include <iostream>

  2. #include <thread>

  3. #include <unistd.h>

  4. using namespace std;

  5. volatile bool flag = false;

  6. void f1() {

  7. for (int i = 0; i < 1000; ++i) {

  8. if (flag) cout << i << " catched" << endl;

  9. else cout << i << " running" << endl;

  10. usleep(10000);

  11. }

  12. }

  13. void f2() {

  14. sleep(1);

  15. flag = true;

  16. throw 1;

  17. }

  18. void run1() {

  19. thread thr(f1);

  20. f2();

  21. thr.join();

  22. }

  23. int main()

  24. {

  25. try {

  26. run1();

  27. } catch(...) {

  28. }

  29. while(1);

  30. }

这段代码中,我们在run1里面发射了一个线程f1,f1是做一个计数工作,在run1里面运行f2,f2在休眠1秒之后抛异常。

运行结果是: 当f2抛异常之后,程序就挂掉了。

这是为什么呢?因为在f2抛出异常之后,run1发生调用栈回退的时候,析构thr了。在析构thr的时候,我们可以看一下gcc的源代码:

 
  1. ~thread()

  2. {

  3. if (joinable())

  4. std::terminate();

  5. }

一旦这个句柄是没有join就调用析构函数,那么调用std::terminate(),这就是程序挂掉的原因。

到这里,似乎就引入了一个疑问,到底这个时候析构了thr,我们更希望发射出来的线程f2应该怎么运行呢?真的希望程序挂掉吗?

分析起来,大致可以有下面两种看起来合理的情况:

1、我们可能希望调用栈回退的时候,等f2运行完,join之后,才完成调用栈回退

2、我们可能希望把f2剥离句柄thr的控制,自己单独运行

这上面两种情况都是可以实现的,我们分别都看一下。我们先来看第一种实现:

 
  1. class SafeThread {

  2. private:

  3. std::thread thr_;

  4. public:

  5. template< class Function, class... Args >

  6. explicit SafeThread(Function&& f, Args&&... args) {

  7. std::thread thr(f, args ...);

  8. thr_.swap(thr);

  9. }

  10. ~SafeThread() {

  11. thr_.join();

  12. }

  13. };

通过这么实现,放到第一段代码的情境中,就会是这样子:

 
  1. void run1() {

  2. SafeThread thr(f1);

  3. f2();

  4. }

这是RAII的实现方式,在离开作用域的时候析构,而我们在析构的时候完成join的工作。那么,在发生刚才那种情况的时候,异常一旦抛出,run1就要做栈回退,当调用thr的析构函数的时候,自然就会join,等待f1的执行完毕。

接着我们看一下第二种实现:

 
  1. class SafeThread {

  2. //...同上一种

  3. ~SafeThread() {

  4. thr_.detach();

  5. }

  6. };

大部分和第一种实现一样,不同之处在于,当调用析构函数的时候,把线程剥离句柄(就像脱缰的野马)

最后分析一下两种方式的

1、第一种方式,可以像原有逻辑一样,在完成f1线程之后,才结束run1函数。但是,无法及时处理异常

2、第二种方式很不推荐,一旦f1线程使用了run1提供的局部对象作为运行参数,那么一旦run1调用回退了,局部变量被回收,而f1继续使用,程序就错掉了,能段错误是最好的结局了。

总结,用RAII的方式封装std::thread,按第一种方式实现,是一个不错的选择。

参考:http://akrzemi1.wordpress.com/2012/11/14/not-using-stdthread/

std thread相关推荐

  1. C++11 新特性之std::thread

    C++11 新特性之std::thread 原文:https://blog.csdn.net/oyoung_2012/article/details/78958274 从C++11开始,C++标准库已 ...

  2. 并发,std::thread

    2019独角兽企业重金招聘Python工程师标准>>> std::thread  定义一个线程对象,并管理关联的线程 备注: 你可以使用 thread 对象来观察和管理在应用程序中的 ...

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

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

  4. C++11学习笔记-----线程库std::thread

    在以前,要想在C++程序中使用线程,需要调用操作系统提供的线程库,比如linux下的<pthread.h>.但毕竟是底层的C函数库,没有什么抽象封装可言,仅仅透露着一种简单,暴力美 C++ ...

  5. C++ std::thread 和 std::jthread 使用详解 (含C++20新特性)

    目录 std::thread std::thread 构造函数 观察器 操作 std::jthread std::jthread 构造函数 观察器 操作 停止记号处理 管理当前线程的函数 yield( ...

  6. std::jthread与std::thread的区别

    特性上,std::jthread相比std::thread主要增加了以下两个功能: 1.std::jthread对象被destruct时,会自动调用join,等待其所表示的执行流结束. 2.支持外部请 ...

  7. c++11仔细地将参数传递给线程std::thread

    要将参数传递给线程的可关联对象或函数,只需将参数传递给std::thread构造函数. 默认情况下,所有的参数都将复制到新线程的内部存储中. 看一个例子: 给线程传递单个参数 #include < ...

  8. std::thread 不 join

    std::thread 构造之后 使用 detach.就可以了

  9. C++11并发编程:多线程std::thread

    一:概述 C++11引入了thread类,大大降低了多线程使用的复杂度,原先使用多线程只能用系统的API,无法解决跨平台问题,一套代码平台移植,对应多线程代码也必须要修改.现在在C++11中只需使用语 ...

最新文章

  1. 深度学习的第一性原理!
  2. vs代码显示波浪线,但没编译错误
  3. 嵌入式研发人员的核心竞争力浅谈 .
  4. hdu5692 Snacks dfs序+线段树
  5. matlab 数据是否符合正态分布的判断方法
  6. 基于ProtocolBuffer和ysocket的Swift即时通讯服务器搭建
  7. Linux 系统批量安装字体的方法
  8. tomcat7解压版安装过程
  9. MFC通过窗口标题获得窗口句柄
  10. opencv codebook背景减除
  11. 手机计算机数据消失了怎么恢复,手机数据丢失的恢复方法
  12. 算法之显著性检测《Saliency Detection: A Spectral Residual A》
  13. 领导和同事嫌弃你的6个征兆,离失业不远了
  14. 文本预处理库spaCy的基本使用(快速入门)
  15. VS2022+PCL 1.12.1
  16. 图说卡尔曼滤波(C++实现)
  17. python培训报告,简述Python语言经验总结_python知识点总结_python培训
  18. java模拟回合制游戏大小姐_[源码和文档分享]基于java的RPG回合制游戏
  19. AD16画PCB流程及集成库制作注意事项
  20. 硕士论文中期汇报ppt_华北理工大学附属唐山市人民医院硕士学位论文开题、中期汇报会圆满结束...

热门文章

  1. INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES错误解决方法
  2. variable java_在XSLT中使用Variable Argument调用Java方法
  3. 计算机组成原理考试知识点总结,最新2018计算机组成原理期末复习考试知识点复习考点归纳总结总结...
  4. 问题集锦(56-57)
  5. binostat matlab,MATLAB概率统计函数(2)
  6. java 互斥量_什么是Java中的互斥和信号量?主要区别是什么?
  7. intellij_使用IntelliJ ..已经2周了,到目前为止还算不错
  8. matlab 2009a使用教程,实验一 安装MATLAB R2009a软件及其简单操作
  9. android 8.0的imei简书,Android 8.0通知栏渠道,渠道组的适配和使用
  10. js java cookie_JS 打开一个模式窗口,使用Cookie传递一个参数