当前位置: 首页 > news >正文

C++ 20新特性之线程与jthread

💡 如果想阅读最新的文章,或者有技术问题需要交流和沟通,可搜索并关注微信公众号“希望睿智”。

为什么要引入jthread

        在C++ 11中,已经引入了std::thread。std::thread为C++标准库带来了一流的线程支持,极大地促进了多线程开发的便利性。但std::thread也存在一些明显的不足和短板,主要有以下几点。

        1、生命周期管理的复杂性。std::thread对象必须在它代表的线程结束之前,一直保持存活。如果一个std::thread对象被销毁(比如:离开了其作用域),而它关联的线程还在运行,那么程序会调用std::terminate()终止,除非线程被join或者detach过。这就要求我们必须仔细管理每个线程对象的生命周期,大大增加了编码的复杂度和出错的可能性。

        2、缺乏自动资源管理。std::thread没有自动管理线程生命周期的机制,程序员必须显式调用join或detach。否则,可能导致资源泄露或程序异常终止,这在异常处理场景下尤为麻烦。

        3、异常安全性问题。如果在创建或启动std::thread时发生异常,可能会导致资源泄露或者程序的不确定行为。比如:如果在std::thread构造函数中抛出了异常,那么已经创建的线程可能无法正确地被join或detach。

        为了解决这些问题,C++ 20中引入了std::jthread。

自动管理生命周期

        C++ 20中新引入的std::jthread解决了C++ 11中std::thread的一些不便之处,特别是在线程生命周期管理上的自动化处理。std::jthread是一个智能指针风格的类,它自动join或detach与之关联的线程,从而避免了潜在的资源泄露问题。

        接下来,我们通过一个具体的例子来理解std::jthread的工作原理。

#include <iostream>
#include <thread>
using namespace std;void RunTask(stop_token stoken)
{int nCount = 0;while (!stoken.stop_requested()){cout << "Task running... " << nCount++ << endl;this_thread::sleep_for(chrono::seconds(1));}cout << "Task stopped" << endl;
}int main()
{jthread t(RunTask);// 主线程等待一段时间this_thread::sleep_for(chrono::seconds(5));return 0;
}

        在上面的示例代码中,RunTask函数作为工作线程的入口点,接收一个std::stop_token参数,用于检测是否请求停止。std::jthread t(RunTask)声明了一个jthread对象t,它会自动管理task函数所在线程的生命周期。当main函数结束时,t会自动调用join,等待关联线程完成或终止。可以看到,虽然我们没有显式要求停止线程,但当main函数返回时,jthread会确保线程安全结束。执行这段代码,其输出如下。

Task running... 0
Task running... 1
Task running... 2
Task running... 3
Task running... 4
Task stopped

stop_source和stop_token

        与std::thread相比,std::jthread的强大之处在于它与std::stop_source和std::stop_token的集成,从而允许我们优雅地请求线程停止。

        在下面的示例代码中,通过创建std::stop_source对象,并将其get_token方法的结果传递给RunTask函数,我们可以在需要时通过stopSource.request_stop()请求线程停止。RunTask函数中会循环检查std::stop_token的状态,一旦请求停止,就会退出循环并清理资源。

#include <iostream>
#include <thread>
using namespace std;void RunTask(stop_token stoken)
{int nCount = 0;while (!stoken.stop_requested()){// 子线程执行一些任务cout << "Working..." << nCount++ << endl;this_thread::sleep_for(chrono::seconds(1));}cout << "Task stopped" << endl;
}int main()
{stop_source stopSource;jthread t(RunTask, stopSource.get_token());// 主线程等待一段时间this_thread::sleep_for(chrono::seconds(3));cout << "Request task to stop..." << endl;// 主动请求线程停止stopSource.request_stop();return 0;
}

        执行上述代码,其输出如下。

Working...0
Working...1
Working...2
Request task to stop...
Task stopped

线程中使用成员函数

        std::jthread不仅可以用来启动普通函数,还可以用来启动类的成员函数。此时,需要使用lambda表达式来传递对象实例和成员函数指针。具体的用法,可以参考下面的示例代码。

#include <iostream>
#include <thread>
using namespace std;class CTask
{
public:void Run(stop_token stoken){int nCount = 0;while (!stoken.stop_requested()){cout << "Working..." << nCount++ << endl;this_thread::sleep_for(chrono::seconds(1));}}
};int main()
{CTask task;jthread t([&task](stop_token stoken){ task.Run(stoken); });this_thread::sleep_for(chrono::seconds(5));return 0;
}

        在上面的示例代码中,我们首先定义了一个名为CTask的类,其中包含一个公共成员函数Run。这个函数接收一个stop_token参数,用于检查是否有停止线程的请求。函数内部,它使用一个循环不断地输出计数器的值,并在每次循环之间暂停1秒。当stop_token表示停止请求时,循环结束。

        在main函数中,我们创建了CTask类的对象task。接着,声明了一个jthread对象t,并初始化它以执行一个Lambda函数。这个Lambda函数捕获了task对象的引用,并将其传递给task.Run()方法,同时也传入了stop_token。jthread会自动为这个Lambda函数提供一个与之关联的stop_token,用于线程的停止请求。当jthread对象t的生命周期结束时,它会自动调用join来等待线程结束,无需手动调用join或detach。

相关文章:

C++ 20新特性之线程与jthread

&#x1f4a1; 如果想阅读最新的文章&#xff0c;或者有技术问题需要交流和沟通&#xff0c;可搜索并关注微信公众号“希望睿智”。 为什么要引入jthread 在C 11中&#xff0c;已经引入了std::thread。std::thread为C标准库带来了一流的线程支持&#xff0c;极大地促进了多线程…...

赶紧收藏!2024 年最常见 20道并发编程面试题(七)

上一篇地址&#xff1a;赶紧收藏&#xff01;2024 年最常见 20道并发编程面试题&#xff08;六&#xff09;-CSDN博客 十三、什么是线程局部存储&#xff08;Thread-Local Storage&#xff09;&#xff1f; 线程局部存储&#xff08;Thread-Local Storage&#xff0c;简称TLS…...

HAL库开发--第一盏灯

知不足而奋进 望远山而前行 目录 文章目录 前言 学习目标 学习内容 需求 开发流程 项目创建 芯片配置 功能配置 时钟配置 项目配置 编写代码 编译测试 烧录失败解决 ​编辑 总结 前言 在嵌入式系统开发中&#xff0c;掌握HAL库开发流程、STMCubeMX配置过程以及…...

Linux C语言:变量的作用域和生命周期(auto、register、static和extern)

一、变量存储类型-auto 1、auto变量的说明 变量在程序中使用时,必须预先说明它们的存储类型和数据类型。 变量说明的一般形式是&#xff1a; <存储类型> <数据类型 > <变量名> &#xff1b; <存储类型>是关键词auto、register、static和extern<…...

AI Stable diffusion 报错:稳定扩散模型加载失败,退出

可能是内存不够&#xff0c;看看你最近是加了新的大的模型&#xff0c;可以把你的stable-diffusion-webui\models\Stable-diffusion目录下的某个ckpt删除掉&#xff0c;可能ckpt太大&#xff0c;无法加载成功&#xff1b; Stable diffusion model failed to load, exiting 如图…...

[Python学习篇] Python循环语句

while 循环 语法&#xff1a; while 条件: 条件成立后会重复执行的代码 ...... 示例1&#xff1a;死循环 # 这是一个死循环示例 while True:print("我正在重复执行")示例2&#xff1a;循环指定次数 i 1 while i < 5:print(f"执行次数 {i}")…...

MongoDB 正则表达式

MongoDB 正则表达式 MongoDB 是一个流行的 NoSQL 数据库&#xff0c;它提供了强大的查询功能&#xff0c;包括对正则表达式的支持。正则表达式是一种强大的文本搜索工具&#xff0c;它允许用户根据特定的模式匹配和搜索字符串。在 MongoDB 中&#xff0c;正则表达式可以用于查…...

Django配置连接池:使用django-db-connection-pool配置连接池

一、该三方库文档使用 github地址&#xff1a; https://github.com/altairbow/django-db-connection-pool/blob/1.2.5/README_CN.mdhttps://github.com/altairbow/django-db-connection-pool/blob/1.2.5/README_CN.md1、选择指定版本&#xff0c;查看指定版本的文档和配置&am…...

SpringBoot整合钉钉实现消息推送

前言 钉钉作为一款企业级通讯工具&#xff0c;具有广泛的应用场景&#xff0c;包括但不限于团队协作、任务提醒、工作汇报等。 通过Spring Boot应用程序整合钉钉实现消息推送&#xff0c;我们可以实现以下功能&#xff1a; 实时向指定用户或群组发送消息通知。自定义消息内容…...

【机器学习】集成学习方法:Bagging与Boosting的应用与优势

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 引言一、集成学习的定义二、Bagging方法1. 随机森林&#xff08;Random Forest&#xff09;2. 其他Bagging方法 二、Boosting方法1. 梯度提升树&#xff08;Gradient Boosting Machine, GBM&#xff09;解释GBM的基本原理和…...

工业 web4.0 的 UI 卓越非凡

工业 web4.0 的 UI 卓越非凡...

C语言 | Leetcode C语言题解之第145题二叉树的后序遍历

题目&#xff1a; 题解&#xff1a; void addPath(int *vec, int *vecSize, struct TreeNode *node) {int count 0;while (node ! NULL) {count;vec[(*vecSize)] node->val;node node->right;}for (int i (*vecSize) - count, j (*vecSize) - 1; i < j; i, --j)…...

如何在 Vue 3 中使用 vue3-print-nb 实现灵活的前端打印

你好&#xff0c;我是小白Coding日志&#xff0c;一个热爱技术的程序员。在这里&#xff0c;我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客&#xff0c;一起在技术的世界里探索前行吧&#xff01; 前言 在前端开…...

Go Module详解

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…...

基于51单片机的智能水表

一.硬件方案 本设计主要以51单片机作为主控处理器的智能水表&#xff0c;该水表能够记录总的用水量和单次用水量&#xff0c;当用水量超出设定值时系统发出声光报警提醒&#xff0c;水量报警值能够通过按键进行自行设置&#xff0c;并且存储于AT24C02中&#xff0c;并且可以测…...

SQLServer 借助Navcate做定时备份的脚本

首先创建SQLServer链接&#xff0c;然后在Query标签种创建一个查询 查询内容如下 use ChengYuMES declare ls_time varchar(1000) declare ls_dbname varchar(1000) set ls_time convert(varchar, getdate(), 112) _ replace(convert(varchar, getdate(), 108), :, )-- 需…...

MBD_入门篇_21_SimulinkSignalAttributes

21.SignalAttributes 21.1 概述 Signal Attributes&#xff0c;信号属性&#xff0c;信号特性。 21.2 回顾常用模块 21.2.1 DataTypeConversion 数据类型转换模块&#xff0c;可以对信号的数据类型进行强制转换。无符号数据与有符号数据相加&#xff0c;我们可以将无符号数据转…...

Web前端高级课程:深入探索与技能飞跃

Web前端高级课程&#xff1a;深入探索与技能飞跃 在数字化时代的浪潮中&#xff0c;Web前端技术日新月异&#xff0c;对前端开发者的技能要求也日益提高。为了满足这一需求&#xff0c;我们精心打造了一款Web前端高级课程&#xff0c;旨在帮助学员掌握最前沿的前端技术&#x…...

螺丝工厂vtk ThreadFactory(1)

螺丝工厂vtkThreadFactory (1) 缘起 几年前的探索在Python里应用Openscad实现3D建模之3D螺纹建模初探3 新的参考: generating nice threads in openscadvtkRotationalExtrusionFilter 辅助AI: coze 笔记&#x1f4d2;: openscad 代码分析 // 半径缩放函数&#xff0c;用…...

Android13 蓝牙协议属性配置详解

Android13 蓝牙协议属性配置详解 文章目录 Android13 蓝牙协议属性配置详解一、前言二、Android13 蓝牙协议属性配置1、Profile 属性和暴露接口的定义2、蓝牙协议属性定义3、系统代码中判断蓝牙协议是否使能的代码 三、其他1、adb 窗口中查看蓝牙协议属性2、动态设置蓝牙prop协…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?

FTP&#xff08;File Transfer Protocol&#xff09;本身是一个基于 TCP 的协议&#xff0c;理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况&#xff0c;主要原因包括&#xff1a; ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...

论文阅读:Matting by Generation

今天介绍一篇关于 matting 抠图的文章&#xff0c;抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法&#xff0c;已经有很多的工作和这个任务相关。这两年 diffusion 模型很火&#xff0c;大家又开始用 diffusion 模型做各种 CV 任务了&am…...