C++ 多线程的错误和如何避免(1)
在终止程序之前没有使用 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
四种可以安全析构的情况是:
- 默认构造函数创建的 std::thread,在这种情况下,没有实际的线程被创建。
- 被移动过的线程,在这种情况下,移动的对象关联了线程而被移动的对象无关联线程。
- 调用了 join(),在这种情况下,join() 函数会堵塞直到被关联的线程执行结束。
- 调用了detach(),在这种情况下,被关联的线程会被解除关联。
参考:
C++ 多线程的错误和如何避免(1)的更多相关文章
- c++多线程崩溃错误1
主线程中的子线程没有jion,导致主线程马上结束,子线程对象被释放掉,而子线程还在后台继续执行导致崩溃 int main() OBJ = classA() OBJ.START()//在start函数中 ...
- Java SE之快速失败(Fast-Fail)与快速安全(Fast-Safe)的区别[集合与多线程/增强For](彻底详解)
声明 特点:基于JDK源码进行分析. 研究费时费力,如需转载或摘要,请显著处注明出处,以尊重劳动研究成果:博客园 - https://www.cnblogs.com/johnnyzen/p/10547 ...
- Java多线程知识总结(一)
一.创建线程的三种方式: 创建线程的方式有三种,一是创建Thread实例,二是实现Runnable接口,三是实现Callable接口,Runnable接口和Callable接口的区别是一个无返回值,一 ...
- Java回顾之多线程同步
在这篇文章里,我们关注线程同步的话题.这是比多线程更复杂,稍不留意,我们就会“掉到坑里”,而且和单线程程序不同,多线程的错误是否每次都出现,也是不固定的,这给调试也带来了很大的挑战. 在这篇文章里,我 ...
- 2019年北航OO第二单元(多线程电梯任务)总结
一.三次作业总结 1. 说在前面 对于这次的这三次电梯作业,我采用了和几乎所有人都不同的架构:将每个人当作一个线程.这样做有一定的好处:它使得整个问题的建模更加自然,并且在后期人员调度变得复杂时,可以 ...
- 转:最近5年133个Java面试问题列表
最近5年133个Java面试问题列表 Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来 ...
- [转载]hashmap hashtable 的区别
Hashtable 和 HashMap 做为 Map 的基本特性 两者都实现了Map接口,基本特性相同 - 对同一个Key,只会有一个对应的value值存在 - 如 ...
- Java笔试题解答和部分面试题
面试类 银行类的问题 问题一:在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? HashMap本身没有什么问题,有没有问题取决于你是如何使用它的.比如,你 ...
- Java 集合系列 11 hashmap 和 hashtable 的区别
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- 面试题_76_to_81_Java 最佳实践的面试问题
包含 Java 中各个部分的最佳实践,如集合,字符串,IO,多线程,错误和异常处理,设计模式等等. 76)Java 中,编写多线程程序的时候你会遵循哪些最佳实践?(答案)这是我在写Java 并发程序的 ...
随机推荐
- [转帖]使用JAYDEBEAPI同时连接两个不同数据库(ORACLE+MYSQL)的问题
jaydebeapi 同时连接两种数据库 在使用jaydebeapi只连接一种数据库时,是没问题的,但是如果需要同时连接两种数据库,比如同时连接oracle和mysql 例如以下测试代码: imp ...
- [转帖]公钥基础设施(PKI,Public Key Infrastructure)闲谈
https://zhuanlan.zhihu.com/p/384436119 背景 在现实空间中,人类的活动范围和接触人的范围有限,人和人最初的信任是建立在小团体或部落内部.随着全球化进展,人类的活动 ...
- [转帖]02-rsync备份方式
https://developer.aliyun.com/article/885789?spm=a2c6h.24874632.expert-profile.283.7c46cfe9h5DxWK 简介: ...
- [转帖]linux学习:sed与awk与tr用法整理
https://www.cnblogs.com/LO-gin/p/6882490.html 流编辑器:sed 语法:sed [-hnV][-e<script>][-f<script文 ...
- [转帖]【JVM】线程安全与锁优化
线程安全 1.定义 当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果 2. ...
- Oracle 建立数据库dblink 然后同步部分表内容的总结
同步处理部分数据 背景 最近在项目上发现两个分库进行数据同步时部分内容同步存在问题. 最简单的方法是导表,但是害怕有其他关联信息异常, 所以同事想到了dblink的方式. 这里简单整理一下 同事用到的 ...
- VOP 消息仓库演进之路|如何设计一个亿级企业消息平台
作者:京东零售 李孟冬 VOP作为京东企业业务对外的API对接采购供应链解决方案平台,一直致力于从企业采购数字化领域出发,发挥京东数智化供应链能力,通过产业链上下游耦合与链接,有效助力企业客户的成本优 ...
- 一文详解 Netty 组件
作者:京东物流 张弓言 一.背景 Netty 是一款优秀的高性能网络框架,内部通过 NIO 的方式来处理网络请求,在高负载下也能可靠和高效地处理 I/O 操作 作为较底层的网络通信框架,其被广泛应用在 ...
- interface{}类型 + fmt.Sprintf() 导致栈逃逸
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 对部分代码进行了栈逃逸检查: go build -gcfl ...
- Jupyter Notebook 下 import 第三方库,显示 no module xxx 【本质是环境没有切换过来】
1.最简单情况下 切换环境即可 首先激活环境: activate env # 激活你的环境名称 jupyter notebook 之后去运行代码即可,如果还不行请看下面: 2.遇到Jupyt ...