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

C++20中的jthread

一、多线程开发

c++11以前,是不包含线程库的,开发多线程,必须使用OS系统自带的线程API,这就导致了很多问题,最主要的是,跨平台的开发,一般要保持几个主流应用的库的代码支持,特别是对Win平台和Linux平台的两个线程库的支持,否则,就无法实现简单的跨平台的功能。而两个平台的多线程的使用差异和一些细节不同的,比如事件Event在Linux上没有。而条件变量在Win平台上没有,就更容易使一些应用场景的开发的复杂性大幅提高。
而到了c++11以后,提供了std::thread这个多线程的支持,可以说大幅的降低了跨平台开发的复杂性。
但是在实际的应用过程中,又遇到了一些新的需求变化,比如应用的方便性和多线程运行过程中的可操作性及可见性上,都需要提供新的接口。按照c++设计者们的一贯作风,他们不会在基础的std::thread本身进行修改,那么,他们就对这个类进行了再封装,增加了上述的功能,然后提出了std::jthread这个类。

二、jthread的功能和实现

一般来说,接口越丰富,那么这个类功能越强大,但是反过来,缺点就是不容易掌握并且容易忘记调用,在使用std::thread时,有没有忘记调用join()或者detach()的时候?自动调用好不好?线程函数运行过程中,可不可以可以动态请求交互一下,而不是靠各种变量来预先进行控制。对,在std::jthread上都实现了。
看一看标准文档是如何定义的:

std::jthread::jthread
jthread() noexcept;                              (1)	(C++20)
jthread( jthread&& other ) noexcept;             (2)	(C++20)
template< class Function, class... Args >
explicit jthread( Function&& f, Args&&... args );(3)	(C++20)
jthread( const jthread& ) = delete;              (4)	(C++20)

第一个表示创建新的jthread对象;第二个表示移动语义,既然移动了,那么原来线程停止执行线程,由新线程执行;第三个表示线程函数f接受 std::stop_token 作为其首参数,则新线程开始执行:

std::invoke(decay_copy(std::forward<Function>(f)),get_stop_token(),decay_copy(std::forward<Args>(args))...);

;否则它开始执行

std::invoke(decay_copy(std::forward<Function>(f)),decay_copy(std::forward<Args>(args))...);

任一情况下, decay_copy 定义为

template <class T>
std::decay_t<T> decay_copy(T&& v) { return std::forward<T>(v); }

除了在调用方的语境中执行 decay_copy ,故而在求值和移动/构造参数期间抛出的任何异常都在当前线程抛出,而不会开始新线程。
构造函数的完成同步于(按 std::memory_order 中定义) f 的副本在新线程上调用的开始。
若 std::remove_cvref_t 与 std::jthread 为相同类型则此构造函数不参与重载决议。
最后一个表示不可复制,也就是说只能它自己执行线程,没有任何其它一个std::jthread对象可以表示同一线程。

std::jthread的成员函数里,可以看支持查看硬件并发数的函数,交换线程对象的函数,协作请示的函数等,更多的详情可以参看一下:
https://zh.cppreference.com/w/cpp/thread/jthread/jthread
https://zh.cppreference.com/w/cpp/header/stop_token

三、应用

线程的中断和取消是需要高度引起注意的,一不小心,强行KILL的线程中的各种资源或者句柄就没有回收,导致各种泄露。这也是在多线程编程中,普遍有一个要求,就是让线程自己执行完毕退出,而为了这个要求,就需要牺牲一下控制的效率。
当然,先从std::thread的多线程编程的例子看:

#include <Windows.h>
#include <iostream>
#include <thread>
#include <chrono>bool quit = false;void SleepTime(int sec)
{std::this_thread::sleep_for(std::chrono::seconds(sec));
}
void ThreadWorker()
{//work work workstd::cout << "thread start,working! " << std::endl;
}void MainWorker()
{std::cout << "main thread start,working! " << std::endl;
}
int main()
{std::thread t = std::thread([&]() {while (!quit){ThreadWorker();SleepTime(2);}});//Sleep(3);MainWorker();t.join();//t.detach();
}

这个DEMO非常简单,在主线程中启动了一个子线程,需要注意一下注释的延时的情况,主要是起一个先后交替的条件。主线程在执行完成自己的工作后,就会join等待子线程的完成,像上面这种情况,就死循环了,不会停止。如果需要停止只能使用设置quit为True或者强制的命令等不友好的手段了。首先看一下,换成jthread会是啥样?其它代码都没有改变,只是修改了下面的代码:

std::jthread t = std::jthread([&]() {while (!quit){ThreadWorker();SleepTime(2);}
});

需要包含的jthread等的头文件可以去github或者相关的网站上下载,这里只提供一处,并对此表示感谢:
https://github.com/josuttis/jthread/tree/master/source
上面的两处代码的运行结果是完全一样的,没有什么不同。那用这个类的优势呢?别急,把main函数改一下:

int main()
{std::jthread t = std::jthread([&]() {while (!quit){ThreadWorker();SleepTime(2);}});Sleep(3);MainWorker();//t.join();//t.detach();
}

把最后一行注释,再编译运行,仍然没有啥问题,有一点不同了吧。这可以避免粗心大意的同学出现意外错误吧。再看一下,如果设置quit为true,那么线程会怎么办?没啥大问题,到了判断就退出了,可是如果有多个线程在执行,是不是要设置多个类似的变量呢?答案是肯定的。这时候儿看看jthread的协作中断:

int main()
{std::jthread t = std::jthread([&]() {while (!quit){ThreadWorker();SleepTime(2);}});Sleep(3);MainWorker();t.request_stop();//简单增加一行代码
}

编译运行,发现没啥反应,好,再修改一下线程函数:

int main()
{std::jthread t = std::jthread([&](std::stop_token st) {while (/*!quit*/!st.stop_requested()){ThreadWorker();SleepTime(2);}});Sleep(3);MainWorker();//getchar();t.request_stop();//t.join();//t.detach();getchar();
}

这个时候儿发现没啥问题了,注意上面getchar()函数的位置,如果在后面,则执行一次就退出了。如果在前面,就继续不断执行。把t.request_stop();这一行也注释,发现程序仍然和不注释一样,看来这个jthread里做了什么运作,看一下它的析构函数:

inline jthread::~jthread() {if (joinable()) {   // if not joined/detached, signal stop and wait for end:request_stop();join();}
}

明白了吧。至于为什么不用detach(),可能是大牛们觉得join()会更安全一些吧。毕竟等待完成后,所有的对象都被回收了。下面再看官网提供的一个例子:

class foo
{
public:void bar(){for (int i = 0; i < 5; ++i) {std::cout << "Thread 3 executing\n";++n;std::this_thread::sleep_for(std::chrono::milliseconds(10));}}int n = 0;
};
int main()
{foo f;std::jthread t3(&foo::bar, &f);std::jthread t = std::jthread([&](std::stop_token st) {while (/*!quit*/!st.stop_requested()){ThreadWorker();SleepTime(2);}});std::cout << t.hardware_concurrency() << std::endl;Sleep(3);MainWorker();getchar();t.request_stop();//t.join();//t.detach();
}

执行一下,就可以看出上面提到的decay_copy这个模板函数的使用,没啥不容易理解的。

4、总结

其实还有几个特点值得说说,但不准备再讲了,虽然已经投票完成确定了c++20的标准,但毕竟还没有正式增加进去,大家有兴趣可以看看源码。整体来看,c++应用还是越来越方便,这对c++来说,肯定是个好事情。现在就希望>VS2019或者>GCC11中,尽快完全支持。

相关文章:

C++20中的jthread

一、多线程开发 c11以前&#xff0c;是不包含线程库的&#xff0c;开发多线程&#xff0c;必须使用OS系统自带的线程API&#xff0c;这就导致了很多问题&#xff0c;最主要的是&#xff0c;跨平台的开发&#xff0c;一般要保持几个主流应用的库的代码支持&#xff0c;特别是对…...

Xception模型详解

简介 Xception的名称源自于"Extreme Inception"&#xff0c;它是在Inception架构的基础上进行了扩展和改进。Inception架构是Google团队提出的一种经典的卷积神经网络架构&#xff0c;用于解决深度卷积神经网络中的计算和参数增长问题。 与Inception不同&#xff0…...

【合合TextIn】AI构建新质生产力,合合信息Embedding模型助力专业知识应用

目录 一、合合信息acge模型获MTEB中文榜单第一 二、MTEB与C-MTEB 三、Embedding模型的意义 四、合合信息acge模型 &#xff08;一&#xff09;acge模型特点 &#xff08;二&#xff09;acge模型功能 &#xff08;三&#xff09;acge模型优势 五、公司介绍 一、合合信息…...

Flutter 拦截系统键盘,显示自定义键盘

一、这里记录下在开发过程中&#xff0c;下单的时候输入金额需要使用自定义的数字键盘 参考链接: https://juejin.cn/post/7166046328609308685 效果图 二、屏蔽系统键盘 怎样才能够在输入框获取焦点的时候&#xff0c;不让系统键盘弹出呢&#xff1f;同时又显示我们自定义的…...

内存泄漏是什么?如何避免内存泄漏?

1.2 内存泄漏 使用new开辟空间泄漏&#xff0c;抛出异常 int main() {int size 0;try{while (1){//int* p (int*)malloc(sizeof(int) * 1024 * 1024);/*if (p NULL){break;}*/int* p new int[1024 * 1024];size size 4 * 1024 * 1024;cout << p << endl;}}…...

linux 中的syslog的含义和用法

在Linux系统中&#xff0c;syslog是一种系统日志服务&#xff0c;用于收集、存储和管理系统和应用程序生成的日志消息。syslog服务负责记录系统的运行状态、错误信息、警告、调试信息等&#xff0c;以便系统管理员可以监控系统的健康状况、故障排查和性能优化。 含义和作用&am…...

kubernetes(K8S)学习(一):K8S集群搭建(1 master 2 worker)

K8S集群搭建&#xff08;1 master 2 worker&#xff09; 一、环境资源准备1.1、版本统一1.2、k8s环境系统要求1.3、准备三台Centos7虚拟机 二、集群搭建2.1、更新yum&#xff0c;并安装依赖包2.2、安装Docker2.3、设置hostname&#xff0c;修改hosts文件2.4、设置k8s的系统要求…...

巧克力(蓝桥杯)

文章目录 巧克力题目描述解题分析贪心 巧克力 题目描述 小蓝很喜欢吃巧克力&#xff0c;他每天都要吃一块巧克力。 一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力&#xff0c;每种巧克力有自己的价格、数量和剩余的保质期天数&#xff0c;小蓝只吃没过保质期的…...

Python爬虫之pyquery和parsel的使用

三、pyquery的使用 1、准备工作 pip3 install pyquery2、初始化 2.1、字符串初始化 把HTML的内容当做参数&#xff0c;来初始化PyQuery对象。 html <div><ul><li class"item-0">first item</li><li class"item-1">&l…...

移动硬盘怎么加密?移动硬盘加密软件有哪些?

移动硬盘是我们在工作中最常用的移动存储设备&#xff0c;为了保护数据安全&#xff0c;需要使用专业的移动硬盘加密软件加密保护。那么&#xff0c;移动硬盘加密软件有哪些&#xff1f; ​BitLocker BitLocker是Windows的磁盘加锁功能&#xff0c;可以用于加密保护移动硬盘中…...

openEuler 22.03 安装 .NET 8.0

openEuler 22.03 安装 .NET 8.0 openEuler 22.03 安装 .NET 8.0 openEuler 22.03 安装 .NET 8.0 查看内核信息 [jeffPC-20240314EIAA ~]$ cat /proc/version Linux version 5.15.146.1-microsoft-standard-WSL2 (root65c757a075e2) (gcc (GCC) 11.2.0, GNU ld (GNU Binutils)…...

【转载】OpenCV ECC图像对齐实现与代码演示(Python / C++源码)

发现一个有很多实践代码的git 库,特记录下: 地址:GitHub - luohenyueji/OpenCV-Practical-Exercise: OpenCV practical exercise 作者博客地址:https://blog.csdn.net/LuohenYJ 已关注。 Items项目Resources1age_gender1基于深度学习识别人脸性别和年龄Model2OpenCV_dlib_…...

每日一题(相交链表 )

欢迎大家来我们主页进行指导 LaNzikinh-CSDN博客 160. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节…...

C#WPF控件大全

本文列出WPF控件大全,点击可以进入详情页查看。 列表如下: AccessText用下划线来指定用作访问键的字符。 ActivatingKeyTipEventArgs为 ActivatingKeyTip 事件提供数据。...

好书推荐 《AIGC重塑金融》

作者&#xff1a;林建明 来源&#xff1a;IT 阅读排行榜 本文摘编自《AIGC 重塑金融&#xff1a;AI 大模型驱动的金融变革与实践》&#xff0c;机械工业出版社出版 这是最好的时代&#xff0c;也是最坏的时代。尽管大模型技术在金融领域具有巨大的应用潜力&#xff0c;但其应…...

【Linux】权限理解

权限理解 1. shell命令以及运行原理2. Linux权限的概念3. Linux权限管理3.1 文件访问者的分类&#xff08;人&#xff09;3.2 文件类型和访问权限&#xff08;事物属性&#xff09;3.2.1 文件类型3.2.2 基本权限 3.3 文件权限值的表示方法3.4 文件访问权限的相关设置方法3.4.1 …...

插入排序、归并排序、堆排序和快速排序的稳定性分析

插入排序、归并排序、堆排序和快速排序的稳定性分析 一、插入排序的稳定性二、归并排序的稳定性三、堆排序的稳定性四、快速排序的稳定性总结 在计算机科学中&#xff0c;排序是将一组数据按照特定顺序进行排列的过程。排序算法的效率和稳定性是评价其优劣的两个重要指标。稳定…...

【pytest、playwright】多账号同时操作

目录 方案实现思路&#xff1a; 方案一&#xff1a; 方案二&#xff1a; 方案实现思路&#xff1a; 依照上图所见&#xff0c;就知道&#xff0c;一个账号是pytest-playwright默认的环境&#xff0c;一个是 账号登录的环境 方案一&#xff1a; 直接上代码&#xff1a; imp…...

软考 系统架构设计师系列知识点之云原生架构设计理论与实践(8)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之云原生架构设计理论与实践&#xff08;7&#xff09; 所属章节&#xff1a; 第14章. 云原生架构设计理论与实践 第2节 云原生架构内涵 14.2 云原生架构内涵 关于云原生的定义有众多版本&#xff0c;对于云原生架构的…...

【C++】stack、queue和优先级队列

一、前言 二、stack类 2.1 了解stack 2.2 使用stack &#xff08;1&#xff09;empty &#xff08;2&#xff09;size &#xff08;3&#xff09;top &#xff08;4&#xff09;push &#xff08;5&#xff09;pop 2.3 stack的模拟实现 三、queue类 3.1 了解queue …...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...