C++一文讲透thread中的detach和join的差别

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、thread详解
  • 二、线程何时运行
  • 三、线程启动方式
    • 1.join
    • 2.detach
  • 总结


前言

无论哪种语言线程在绝大多数项目中都是会用到的,C++也一样,C++包装了一个std::thread类可以简化程序员的编程,但在使用过程中也要注意区分用法,否则可能适得其反。

今天要讨论的就是单纯的thread的join(等待)和detach(分离)两种情景,让不懂得人看完之后茅塞顿开。


一、thread详解

C++标准库成员,是对线程的包装类,在thread头文件里面,使用方式是std::thread。创建线程本身就是通过创建一个thread类对象然后和系统线程完成绑定(映射),这样可以通过操作thread类对象来管理创建的系统线程,系统线程本身行为受到内核调度机制影响。

示例代码:

#include <iostream>
#include <thread>// 线程函数
void threadFunction() {std::cout << "Thread function is running" << std::endl;
}int main() {// 创建线程并启动std::thread t(threadFunction);// 等待线程完成t.join();std::cout << "Main thread is running" << std::endl;return 0;
}

注意:这个地方如果不使用t.join()可能导致main线程早于子线程结束,引发terminate!

二、线程何时运行

这个问题一定要说清楚才行,我以前用java的时候线程有一个start()可以决定什么时候启动线程,C++则不是这样,C++没有一个明确方法决定线程何时运行,只需要满足创建并等待(一般时间很短,取决于实际情况),直到线程获取了资源之后就会自动运行,而不需要显式调用方法。且无论是以join还是detach方式启动的线程都受到内核的调度。

三、线程启动方式

1.join

主线程(创建子线程的那个线程)等待子线程执行完毕才进行下一步,适合那种需要立刻得到结果的场景。创建方式很简单,你只需要先创建线程然后在合适的时候调用t.join()等待结束即可。

示例代码:

#include <iostream>
#include <thread>int main() {std::thread t([]{std::cout << "Lambda function is running" << std::endl;});t.join();std::cout << "Main thread is running" << std::endl;return 0;
}

当调用t.join()方法时主线程的等待,直到t线程结束主线程才会继续运行,程序结束。如果子线程里面有死锁主线程就会一直等待,永无休止。

2.detach

在C++中,std::thread提供了一个detach方法,可以将线程从其控制对象中分离。分离的线程会在后台独立运行,直到完成。此方法常用于不需要同步或获取线程结果的情况。不过,在使用detach时需要小心,因为主线程不能再控制或管理该分离的线程,这可能会导致资源管理和程序结束时的问题。

另外,detach之后的变量不能重新join。

示例代码:

#include <iostream>
#include <thread>
#include <chrono>void worker() {std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Worker thread finished\n";
}int main() {std::thread t(worker);// 分离线程t.detach();std::cout << "Main thread finished\n";// 此处主线程可能已经结束,而分离的线程仍在运行std::this_thread::sleep_for(std::chrono::seconds(3));  // 确保主线程不会立即退出return 0;
}

创建的子线程很快就会结束,所以主线程3秒的休眠足够了,如果子线程超过3秒就会导致主线程早于子线程结束,程序terminate。

terminate called without an active exceptionProcess finished with exit code 3

所以,还是要面对一个问题,detach后的线程怎么管理?我并不能时时刻刻知道线程的状态,如果主线程结束了子线程没结束怎么办?方法还是有的,那就是增加标志位(同步需要atomic或锁),如果我想一个线程结束只需要修改标志位。比如下面的代码:

#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>std::atomic<bool> keepRunning(true); // 原子布尔变量,用于控制线程执行void threadFunction() {while (keepRunning) {std::cout << "Thread is running..." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));}std::cout << "Thread stopped." << std::endl;
}int main() {std::thread t(threadFunction);// 主线程等待一段时间后停止子线程std::this_thread::sleep_for(std::chrono::seconds(5));keepRunning = false; // 设置标志位,通知线程停止t.join(); // 等待线程结束std::cout << "Main thread is running" << std::endl;return 0;
}

还可以借助boost库的方法来打断线程。例如:

#include <iostream>
#include <boost/thread.hpp>void threadFunction() {try {while (true) {// 执行一些工作boost::this_thread::interruption_point();}} catch (boost::thread_interrupted&) {std::cout << "Thread interrupted." << std::endl;}
}int main() {boost::thread t(threadFunction);// 主线程等待一段时间后中断子线程boost::this_thread::sleep_for(boost::chrono::seconds(5));t.interrupt(); // 中断线程t.join(); // 等待线程结束std::cout << "Main thread is running" << std::endl;return 0;
}

切记,不要随意中断线程,防止资源泄露!不管是标志位、条件判断还是boost库都必须考虑资源回收的问题,否则如果子线程里面使用了自由存储将永远无法得到回收。


总结

不管哪种方式启动的线程都要保证资源的回收,特别是当心主线程早于子线程结束的情况。还有一种容易让人疏忽的情况:如果你在一个函数里创建了thread对象,你没有join或detach,如果在函数return前线程没被回收就会导致terminate。比如,下面的代码:

void test(){
}void thread_join_detach(){std::thread t(test);
//    t.detach();
//    t.join();
}int main() {thread_join_detach();return 0;
}

上面的代码thread_join_detach函数返回会回收t对象,如果线程t还没结束就会terminate。解决方法有很多,比较简单的就是在函数return之前调用join或detach,还有就是把t提升作用域,比如全局变量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/861703.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

昇思25天学习打卡营第9天 | 静态图加速

内容介绍&#xff1a; AI编译框架分为两种运行模式&#xff0c;分别是动态图模式以及静态图模式。MindSpore默认情况下是以动态图模式运行&#xff0c;但也支持手工切换为静态图模式。两种运行模式的详细介绍如下&#xff1a; 动态图模式&#xff1a; 动态图的特点是计算图的…

【Docker项目实战篇】Docker部署PDF多功能工具Stirling-PDF

【Docker项目实战篇】Docker部署PDF多功能工具Stirling-PDF 前言一、Stirling-PDF介绍1.1 Stirling-PDF简介1.2 Stirling-PDF功能 二、本次实践规划2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四…

详解Elastic Search高速搜索背后的秘密:倒排索引

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 全文搜索属于最常见的需求&#xff0c;开源的 Elasticsearch &#xff08;以下简称 Elastic&#xff09;是目前全文搜索引…

Python应用开发——30天学习Streamlit Python包进行APP的构建(10)

st.map 显示一张叠加了散点图的地图。 它是 st.pydeck_chart 的包装器&#xff0c;用于在地图上快速创建散点图表&#xff0c;并具有自动居中和自动缩放功能。 使用该命令时&#xff0c;Mapbox 会提供地图瓦片来渲染地图内容。请注意&#xff0c;Mapbox 是第三方产品&#x…

海云安参编《数字安全蓝皮书 》正式发布并入选《2024中国数字安全新质百强》荣膺“先行者”

近日&#xff0c;国内数字化产业第三方调研与咨询机构数世咨询正式发布了《2024中国数字安全新质百强》&#xff08;以下简称百强报告&#xff09;。海云安凭借在开发安全领域的技术创新力及市场影响力入选百强报告“新质百强先行者” 本次报告&#xff0c;数世咨询经过对国内8…

AJAX 实例:深入解析与实战应用

AJAX 实例:深入解析与实战应用 引言 AJAX(Asynchronous JavaScript and XML)是一种无需重新加载整个网页的情况下,能够更新部分网页的技术。自2005年提出以来,AJAX已成为现代Web开发的重要组成部分,极大地提升了用户体验和网页性能。本文将通过一系列实例,深入解析AJA…

用Verilog实现4位计数器(时序逻辑)

用Verilog实现4位计数器。&#xff08;时序逻辑&#xff09; 实验目的&#xff1a; 通过用Verilog实现4位计数器&#xff0c;进一步熟悉Verilog的语法和时序逻辑电路。 实验描述&#xff1a; 输入&#xff1a; Clock&#xff1a;如果计数器enable信号为1&#xff0c;那么在…

多功能气象传感器的工作原理

TH-WQX9多功能气象传感器是一种集成了多种传感器技术的气象观测装置&#xff0c;旨在同时测量和监测大气中的多个气象要素&#xff0c;以提供全面、准确的气象信息。以下是关于多功能气象传感器的详细介绍&#xff1a; 技术原理 多功能气象传感器采用多种传感器技术相结合&…

深入理解Git:rebase与merge

在Git的版本控制中&#xff0c;rebase和merge是两个至关重要的操作&#xff0c;它们用于整合不同分支的修改。然而&#xff0c;很多开发者在使用时容易混淆&#xff0c;今天我们就来详细解析一下两者的区别、优缺点&#xff0c;并通过实战代码来演示它们的用法。 一、rebase与…

Linux(Ubuntu)下源码开发整个流程完成版本(下载->编译->模拟器运行)

写这篇文章没别的意思, 年纪大了记性不好, 这次工作中下载,编译遇到了一些之前没遇到的问题,所以就所幸记录一下, 以便日后能快速查阅 好了, 正题开始 首先我们下载AOSP源代码开始 AOSP源代码下载 首先找到官网https://source.android.google.cn/ 进入后最上面点击获取源代…

day01-项目介绍及初始化-登录页

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 day01-项目介绍及初始化-登录页一、人力资源项目介绍1.1项目架构和解决方案主要模块解决的问题 二、拉取项目基础代码1.引入库2.升级core-js版本到3.25.5按照完整依…

LSTM时间序列基础学习

时间序列 时间序列可以是一维&#xff0c;二维&#xff0c;三维甚至更高维度的数据&#xff0c;在深度学习的世界中常见的是三维时间序列&#xff0c;这三个维度分别是&#xff08;batch_size,time_step,input_dimensions&#xff09;。 其中time_step是时间步&#xff0c;它…

jenkins中执行docker命令

1. 修改docker.sock文件的所属组 命令如下&#xff1a; sudo chown root:root docker.sock 2. 对这个文件赋予权限&#xff0c;供其他用户使用&#xff0c;给定权限命令如下&#xff1a; sudo chmod orw docker.sock 3. docker容器映射 这里需要两个文件&#xff1a; 一个…

js-iframe-同源策略-addEventListener-postMessage-父子框架

文章目录 1.同源策略2.不同源解决办法-postMessage不受跨域的影响2.1.addEventListener函数监听消息2.2.父传子-不同源2.3.子传父-不同源 3.通过父页面操作子页面-同源3.1.值3.2.函数 4.通过子页面操作父页面-同源4.1.值4.2.函数 1.同源策略 在HTML页面中&#xff0c;我们有时…

等保主机测评防骗指南(资产调研)

你是否测评时常被运维给忽悠&#xff1f;是否觉得以下的对话耳熟&#xff1f; 你&#xff1a;您好&#xff0c;请问你们的主机资产有哪些&#xff0c;包括服务器、数据库、中间件、应用系统等。 甲&#xff1a;我们资产就这两台服务器&#xff0c;数据库什么的都这上面&#…

中断的“挂起状态”

中断的“挂起状态”&#xff08;Pending State&#xff09;是指中断信号已经被系统识别&#xff0c;但尚未被处理器处理的状态。在微控制器或计算机系统中&#xff0c;中断通常是程序外部事件&#xff08;如硬件设备的信号&#xff09;触发的信号&#xff0c;用于通知处理器需要…

C++关键字总结

1.数据类型 bool:布尔类型&#xff0c;属于基本类型的整数类型&#xff0c;取值为真和假 true:具有布尔类型的字面量&#xff0c;表示真 false:具有布尔类型的字面量&#xff0c;表示假 char:表示字符型&#xff0c;定义了字节的大小&#xff0c;char表示单字节字符 wchar_t:表…

蛇形矩阵(xmuoj)

描述 输入两个整数n和m&#xff0c;输出一个n行m列的矩阵&#xff0c;将数字11到nm按照回字蛇形填充至矩阵中。 具体矩阵形式可参考样例。 输入 输入共一行&#xff0c;包含两个整数n和m。 输出 输出满足要求的矩阵。 矩阵占n行&#xff0c;每行包含m个空格隔开的整数。…

TMGM:ASIC撤销禁令,TMGM强化合规、重启差价合约服务

TMGM作为差价合约&#xff08;CFDs&#xff09;与保证金外汇交易领域的领航者&#xff0c;安全、合规、高效被奉为我集团的终身使命。澳大利亚证券和投资委员会&#xff08;ASIC&#xff09;已正式撤销了早前针对TMGM差价合约业务实施的临时止损令。这一误会的解除&#xff0c;…

降低IT运营成本,提升客户体验 |LinkSLA亮相第十届CDIE

6月25-26日&#xff0c;中国数字化创新博览会&#xff08;CDIE 2024&#xff09;在上海张江科学会堂举行。本届展览主题为“AI创新&#xff0c;引领商业增长新格局”&#xff0c;旨在交流企业在数字化时代&#xff0c;如何以科技为驱动&#xff0c;在转型中如何把握机遇&#x…