在终止程序之前没有使用 join() 等待后台线程

前提分析:线程分为 joinable  状态和 detached 状态

添加 .join() 这句代码的时候,就表示主线程需要等待子线程运行结束回收掉子线程的资源后,再往下运行,否则就会产生一种情况:当子线程还没有运行完主线程先运行完了,那么就会结束这个进程,从而中断了子线程的运行。因此 join()函数的作用就是使主线程在此阻塞,等待子线程运行结束并回收其资源,再往下运行。

添加 .detach() 的作用是将主线程与子线程分离,主线程将不再等待子线程的运行,也就是说两个线程同时运行,当主线程结束的时候,进程结束。

在 detach  的时候,这个子线程将脱离主线程的控制,子线程独立分离出去并在后台运行。当主线程结束的时候,进程也就结束,所以子线程的输出不再显示出来,但是不会中断,会在后台继续运行,当子线程运行完以后,资源会被运行时库进行回收。

问题:如果我们在主程序终止之前忘记 join 或 detach,则会导致程序崩溃。

比如:

#include <iostream>
#include <thread> using namespace std; void LaunchRocket() { cout << "Launching Rocket" << endl; } int main() {
thread t1(LaunchRocket);
// t1.join(); // somehow we forgot to join this to main thread - will cause a
// crash.
return 0;
}

运行后,会报错。

解析:

这是因为在 main 函数结束时,线程 t1 超出范围后会自动析构,在析构过程中,会有一个检查来观察线程 t1 是否是 joinable 状态,如果是 joinable 状态,则调用 std::terminate

~thread() _NOEXCEPT
{ // clean up
if (joinable())
_XSTD terminate();
}

而我们创建的 t1 没有添加 .join(),还处于 joinable 状态,此时析构时会调用 terminate(),而 terminate() 会默认调用 abort(),从而报错

补充:

1. joinable() 代表该线程是可执行线程,用于检测线程是否有效。

它会返回一个布尔值来表示当前的线程是否是可执行线程(能被 join 或者 detach),因为相同的线程不能 join 两次,也不能 join  完再  detach,同理也不能 detach

通常以下几种情况会导致线程成为 not-joinable

1)由 thread 的缺省构造函数而造成的(thread() 没有参数)。

2)该 thread 被 move 过(包括 move 构造和 move 赋值)。

3)该线程被 join 或者 detach 过。

比如:

...

if (t1.joinable()) {
cout << "joinable() == true" << endl; // 没有添加 .join(),joinable() == true
} else {
cout << "joinable() == fasle" << endl; // 添加 .join(),joinable() == true
} ...

2. 摘自 https://en.cppreference.com/w/cpp/thread/thread/~thread

四种可以安全析构的情况是:

  1. 默认构造函数创建的 std::thread,在这种情况下,没有实际的线程被创建。
  2. 被移动过的线程,在这种情况下,移动的对象关联了线程而被移动的对象无关联线程。
  3. 调用了 join(),在这种情况下,join() 函数会堵塞直到被关联的线程执行结束。
  4. 调用了detach(),在这种情况下,被关联的线程会被解除关联。

参考:

1. C++ 线程问题,为什么会崩溃?

2. C++ 多线程中的join, detach, joinable

3. Top 20 C++ multithreading mistakes and how to avoid them

C++ 多线程的错误和如何避免(1)的更多相关文章

  1. c++多线程崩溃错误1

    主线程中的子线程没有jion,导致主线程马上结束,子线程对象被释放掉,而子线程还在后台继续执行导致崩溃 int main() OBJ = classA() OBJ.START()//在start函数中 ...

  2. Java SE之快速失败(Fast-Fail)与快速安全(Fast-Safe)的区别[集合与多线程/增强For](彻底详解)

    声明 特点:基于JDK源码进行分析. 研究费时费力,如需转载或摘要,请显著处注明出处,以尊重劳动研究成果:博客园 - https://www.cnblogs.com/johnnyzen/p/10547 ...

  3. Java多线程知识总结(一)

    一.创建线程的三种方式: 创建线程的方式有三种,一是创建Thread实例,二是实现Runnable接口,三是实现Callable接口,Runnable接口和Callable接口的区别是一个无返回值,一 ...

  4. Java回顾之多线程同步

    在这篇文章里,我们关注线程同步的话题.这是比多线程更复杂,稍不留意,我们就会“掉到坑里”,而且和单线程程序不同,多线程的错误是否每次都出现,也是不固定的,这给调试也带来了很大的挑战. 在这篇文章里,我 ...

  5. 2019年北航OO第二单元(多线程电梯任务)总结

    一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...

  6. 转:最近5年133个Java面试问题列表

    最近5年133个Java面试问题列表 Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来 ...

  7. [转载]hashmap hashtable 的区别

    Hashtable 和 HashMap 做为 Map 的基本特性 两者都实现了Map接口,基本特性相同 -          对同一个Key,只会有一个对应的value值存在 -          如 ...

  8. Java笔试题解答和部分面试题

    面试类  银行类的问题 问题一:在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? HashMap本身没有什么问题,有没有问题取决于你是如何使用它的.比如,你 ...

  9. Java 集合系列 11 hashmap 和 hashtable 的区别

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  10. 面试题_76_to_81_Java 最佳实践的面试问题

    包含 Java 中各个部分的最佳实践,如集合,字符串,IO,多线程,错误和异常处理,设计模式等等. 76)Java 中,编写多线程程序的时候你会遵循哪些最佳实践?(答案)这是我在写Java 并发程序的 ...

随机推荐

  1. [转帖]Shell编程规范与变量

    目录 一.Shell的概念 Shell脚本的概念 Shell脚本应用场景 二.Shell的作用 Shell脚本种类 shell脚本的作用 Shell脚本的构成 Shell脚本的构成 二.编写Shell ...

  2. [转帖]Shell字符串拼接(连接、合并)

    http://c.biancheng.net/view/1114.html 在脚本语言中,字符串的拼接(也称字符串连接或者字符串合并)往往都非常简单,例如: 在 PHP 中,使用.即可连接两个字符串: ...

  3. [转帖]Elasticsearch8关闭安全认证功能

    https://juejin.cn/post/7203637198120878137 Elasticsearch8在默认情况下是开启安全认证的.但在开发或者简单尝试时,希望关闭它. 关闭安全认证的方式 ...

  4. [转帖]Linux—CPU核数、上下文切换介绍及pidstat等命令详解

    https://www.jianshu.com/p/0ae0c1153c34 关注:CodingTechWork,一起学习进步. 引言 并发编程   并发编程的目的是为了改善串行程序执行慢问题,但是, ...

  5. 【图论,网络流】CF1525F Goblins And Gnomes

    Problem Link 你在打怪.你有一个 \(n\) 个点 \(m\) 条边的 DAG,接下来会有 \(k\) 波怪来袭,第 \(i\) 波怪有 \(i\) 个,它们会各自选择走一条路径,要求它们 ...

  6. 【K哥爬虫普法】房产数据刑吗?爬虫多年没踩过缝纫机,劝你找找自己原因!

    我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K哥特设了"K哥爬虫普法"专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识,知 ...

  7. 【JS 逆向百例】X球投资者社区 cookie 参数 acw_sc__v2 加密分析

    关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...

  8. 消息队列RabbitMQ教程

    RabbitMQ教程 翻译自RabbitMQ Tutorials. 0. 准备 前期准备 1. Hello World 最简入门教程 2. 工作队列 竞争消费者模式 3. 发布/订阅 同时发送消息给多 ...

  9. .NET 使用Camunda快速入门

    简介参考:https://www.cnblogs.com/lvdeyinBlog/p/16095603.html 一.工作流介绍 1. 什么是工作流 工作流(Workflow),是对工作流程及其各操作 ...

  10. SqlSugar常见问题汇总

    1.已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭. There is already an open DataReader associated with this ...