文章目录

  • 线程管理基础
    • 启动线程
    • C++'s most vexing parse
    • join或detach
    • 在发生异常的情况下join
    • detach

线程管理基础

启动线程

每个程序至少有一个线程:执行main()函数的线程,其余线程有其各自的入口函数。线程与原始线程(以main()为入口函数的线程)同时运行。
使用C++线程库启动线程,可以归结为构造 std::thread 对象,其构造函数传入的参数是可调用对象。

void do_some_work();
std::thread my_thread(do_some_work);

C++'s most vexing parse

需要注意一个关于C++语法解析的问题:“C++’s most vexing parse”

class background_task
{public:void operator()() const{do_something();do_something_else();}
};
background_task f;
std::thread my_thread(f);

这里我们构造了一个函数对象f,并传入thread的构造函数中。如果我们直接这么写

std::thread my_thread(background_task());

我们本意是希望使用background_task的构造函数返回一个background对象,并直接用这个临时对象构造一个thread对象。但是在C++中,上面的表达式会被解析为:声明了一个my_thread函数,返回值为thread对象,参数为一个函数指针,这个函数指针指向的函数没有参数,且其返回值background_task对象。
为了避免这种歧义发生,除了提前声明一个函数对象之外,还可以:

  1. 新增一对括号
std::thread my_thread((background_task()));
  1. 使用初始化语法
std::thread my_thread{background_task()};

join或detach

thread对象构造完成(线程开始执行)之后,对象析构之前,我们必须选择是等待它(join)或者让它在后台运行(detach),如果你在thread对象析构前没有这么做,那么线程将会终止,因为thread的析构函数中调用了std::terminate()

  • detach使得即使thread对象析构,线程也能继续运行,但是注意,我们要确保线程结束之前它所访问的数据都是有效的。
  • 调用thread对象的join方法,函数将等待该线程完成,然后继续执行后续语句。join将清理线程相关的存储空间

thread对象只能join或detach一次,调用过join或detach的对象再调用joinable将返回false

在发生异常的情况下join

在使用detach的时候,我们通常在构造完thread对象就立即调用detach了;而join的位置则会选在thread对象析构之前的某个位置,如果在join之前发生了异常,函数将终止,join不会被调用。为了避免这种情况发生,我们可以加上try-catch语句,并且通常来说,我们希望即使发生异常也调用join方法等待。

struct func;
void f()
{int some_local_state=0;func my_func(some_local_state);std::thread t(my_func);try{do_something_in_current_thread();}catch(...){t.join();throw;}t.join();
}

这种写法过于冗长,我们的目标本质上是希望线程完成之后函数再退出,有一种简洁的方式可以达到这个目的:资源获取就是初始化(RAII,Resource Acquisition Is Initialization)

class thread_guard
{std::thread &t;
public:explicit thread_guard(std::thread &t_) : t(t_){}~thread_guard(){if (t.joinable()){t.join();}}thread_guard(thread_guard const &) = delete;thread_guard &operator=(thread_guard const &) = delete;
};
struct func;
void f()
{int some_local_state = 0;func my_func(some_local_state);std::thread t(my_func);thread_guard g(t);do_something_in_current_thread();
}

当f函数执行结束时,局部变量析构的顺序与构造顺序相反,即先析构g,再析构t,在thread_gurad的析构函数中调用了join函数,即使do_something_in_current_thread发生异常,join函数也会被调用(实际并不是??)。因为线程只能被join一次,因此要先判断是否joinable。
这里删除了默认的拷贝构造函数和拷贝赋值函数,这是因为拷贝后的对象的生命周期可能会超出thread对象的作用域(例如函数返回一个thread_guard对象)

detach

一旦thread对象调用了detach,线程与thread对象将不再有关联,我们也没有直接的方式与线程通信,也不再能join或detach该线程,此时线程的所有权属于C++运行时库,它保证在线程退出时相关资源被回收。分离的线程通常称为守护进程,它们通常在程序的整个生命周期运行,做一些监控、清理工作。同样的thread对象只能被detach一次

C++-线程的join和detach相关推荐

  1. C++:多线程中的小白(2)线程启动、结束、创建线程、join、detach

    目录 一.范例演示:线程运行的开始和结束 二.其他创建线程的手法 一.范例演示:线程运行的开始和结束 (1)thrad (2)join()函数 (3)detach()函数 (4)joinable()函 ...

  2. 第二节 线程启动、结束、创建线程多个方法、join()、detach()

    1.范例演示线程运行的开始和结束 可执行程序运行起来,生成一个进程,该进程所属的主线程开始自动运行. #include <iostream> #include <vector> ...

  3. 【多线程】join()和detach()的用法

    join()函数的作用是让主线程等待该子线程完成,然后主线程再继续执行.这种情况下,子线程可以安全的访问主线程中的资源.子线程结束后由主线程负责回收子线程资源. 一个子线程只能调用join()和det ...

  4. c++11中thread join和detach的区别

    线程状态: 在一个线程的生存期内,可以在多种状态之间转换,不同的操作系统可以实现不同的线程模型,定义许多不同的线程状态,每个状态还可以包含多个子状态,但大体来说,如下几种状态是通用的: 1)就绪:参与 ...

  5. python线程的注意点(线程之间执行是无序的、主线程会等待所有的子线程执行结束再结束(守护主线程)、线程之间共享全局变量、线程之间共享全局变量数据出现错误问题(线程等待(join)、互斥锁))

    1. 线程的注意点介绍 线程之间执行是无序的 主线程会等待所有的子线程执行结束再结束 线程之间共享全局变量 线程之间共享全局变量数据出现错误问题 2. 线程之间执行是无序的 import thread ...

  6. java进阶 线程池 join用法总结:thread4.join();方法,就表明thread4.join();这个线程受到贵客待遇,直到这个线程执行完,被插入这个方法的载体线程才可以执行。

    那个线程调用join 举例 thread4.join();方法,就表明thread4.join();这个线程受到贵客待遇,直到这个线程执行完,被插入这个方法的载体线程才可以执行. package ja ...

  7. java 线程方法join的简单总结

    虽然关于讨论线程join方法的博客已经很多了,不过个人感觉挺多都讨论得不够全面,所以我觉得有必要对其进行一个全面的总结. 一.作用 Thread类中的join方法的主要作用就是同步,它可以使得线程之间 ...

  8. python threading-单线程 多线程 主线程 子线程 setDeamon join

    python threading-单线程 多线程 主线程 子线程 setDeamon join 单线程 多线程 主线程和子线程 setDaemon() join() 测试多线程下程序运行的时间 创建多 ...

  9. python多线程threading之阻塞线程(join)线程同步和守护线程(setDaemon(True))实例详解

    一.多线程(主线程和子线程同时执行) 1.主线程是程序本身,看不到的,主线程和子线程没有依赖关系,同步执行的,若主线程先执行完,会等子线程执行完毕,程序结束 2.启动一个线程就是把一个函数传入并创建T ...

  10. System Verilog线程——fork join的理解使用

    本文参考绿皮书第七章,线程及其线程间的通信,Verilog HDL A guide to digital design and synthesis 2nd第七章.主要对于begin-end,fork- ...

最新文章

  1. MSDynamicsAX2009成本处理与重估(中文)
  2. java main启动spring_gradle 搭建springMVC项目,main函数启动
  3. ecshop api.php,api.php
  4. centOS安装openoffice的方法
  5. 高通fastboot一键进9008工具_linux高通内核移植工具十教程
  6. 在windows上安装 chocolatey.1.1.0.nupkg
  7. 智能硬件(1)--- 智能硬件开发流程
  8. 微信历史消息java_微信聊天机器人[过年防信息轰炸、自动回复拜年消息]
  9. 多媒体计算机室的好处,多媒体会议室系统带来的好处有什么
  10. php 查看linux硬盘序列号,LINUX获取硬盘序列号
  11. 儿童专注力训练之找不同2、数数
  12. PS--常用操作技巧(一)快捷键
  13. Protobuf 在 Ubuntu18 下的安装和使用
  14. 初始智遥工作流软件——流程设置篇
  15. 如何快速准确的验证QQ邮箱是否开通,是否存在?
  16. 暗影精灵2pro装Linux系统,暗影精灵2不支持linux双系统吗?
  17. beatsx三闪红灯_beatsX耳机维修,beats耳机红灯白灯闪维修,南京beatsX耳机维修
  18. 如何在贵金属白银现货走势分析中积累经验?
  19. 经典:uC/OS-II系统的学习教程之(2)
  20. 《Hadoop Operations》读书笔记 - 4 - 第五章 安装与配置

热门文章

  1. springboot 批量生成条形码图片,并下载
  2. 哈工大计算机系统2022春 大作业 程序人生
  3. Android使用LAME Mp3编码
  4. 僵尸网络是什么;僵尸网络有什么特点
  5. stm32上云实战篇
  6. 方正飞鸿智能信息平台(Fix ES2007)
  7. 大衣哥家的小伟和亚楠还能走多久?
  8. 精力充沛才能走得更远更从容
  9. 经典谢幕千千静听(最终版本)7.0.4 去广告增强版下载
  10. linux 反垃圾邮件网关,反垃圾邮件神器--开源邮件网关ScrolloutF1之二--基本配置