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。

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

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

相关文章

leetcode第709题:转换成小写字母

注意字符不仅有26个英文字母&#xff0c;还有特殊字符。特殊字符的话&#xff0c;原样输出。 public class Solution {public char toLowChar(char c){if(c>a&&c<z){return c;}else if(c>A&&c<Z){int n(int)c32;return (char)n;}return c;}publi…

Java数据结构之ArrayList(如果想知道Java中有关ArrayList的知识点,那么只看这一篇就足够了!)

前言&#xff1a;ArrayList是Java中最常用的动态数组实现之一&#xff0c;它提供了便捷的操作接口和灵活的扩展能力&#xff0c;使得在处理动态数据集合时非常方便。本文将深入探讨Java中ArrayList的实现原理、常用操作以及一些使用场景。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨…

useEffect的概念以及使用(对接口)

// useEffect的概念以及使用 import {useEffect, useState} from reactconst Url"http://geek.itheima.net/v1_0/channels"function App() {// 创建状态变量const [lustGet,setLustGet]useState([]);// 渲染完了之后执行这个useEffect(() > {// 额外的操作&#x…

软考初级网络管理员__标准化基础知识单选题

1.张某购买了一张有注册商标的应用软件光盘&#xff0c;擅自复制出售&#xff0c;则其行为侵犯了()。 注册商标专用权 光盘所有权 软件著作权 软件著作权与商标权 2.以下关于软件著作权产生的时间&#xff0c;表述正确的是()。 自软件首次公开发表时 自开发者有开发意图…

如何进行两表数据合并-即包含两张表的所有数据

如果第二张表的数据量多于第一张表&#xff0c;并且您希望最终的表包含两张表的所有数据&#xff0c;即使某些数据在一张表中不存在&#xff0c;可以使用FULL OUTER JOIN。然而&#xff0c;需要注意的是&#xff0c;MySQL不支持FULL OUTER JOIN&#xff0c;但是可以通过结合LEF…

红队攻防渗透技术实战流程:组件安全:SolrShirolog4j

红队攻防渗透实战 1. 组件安全1.1 Solr1.1.1 命令执行(CVE-2019-17558)1.1.2 远程命令执行漏洞(CVE-2019-0193)1.1.3 Apache Solr 文件读取&SSRF (CVE-2021-27905)1.2 Shiro:1.2.1 CVE_2016_4437 Shiro-550+Shiro-7211.2.2 CVE-2020-119891.2.3 CVE-2020-19571.2.4 CVE-…

【TypeScript】泛型工具

跟着 小满zs 学 ts&#xff1a;学习TypeScript24&#xff08;TS进阶用法-泛型工具&#xff09;_ts泛型工具-CSDN博客 Partial 所有属性可选的意思Required 所有属性必选的意思Pick 提取部分属性Exclude 排除部分属性emit 排除部分属性并且返回新的类型 Partial 属性变为可选。…

Qt-Advanced-Docking-System的学习

Qt5.12实现Visual Studio 2019 拖拽式Dock面板-Qt-Advanced-Docking-System_c_saide6000-GitCode 开源社区 (csdn.net) 我使用的是Qt5.5.0 开始&#xff0c;我下载的是最新版的源码&#xff1a;4.1版本 但是&#xff0c;打开ads.pro工程文件&#xff0c;无法编译成功。 然后…

RERCS系统开发实战案例-Part02 创建BOPF对应的业务对象(Business Object)

1、通过事务码 BOBF创建业务对象 2、输入debug&#xff0c;进入编辑模式新建BO对象&#xff1b; 选择对应的BO对象属性类别&#xff1a; 3、激活BO对象 接口页签&#xff1a; 属性页签&#xff1a;自动带出标准的常量 改接口类部分源码&#xff1a; 4、BO对象Node Elemen…

Golang的Gin框架

目录 功能以及简单使用 gin.Engine数据结构 RouterGroup methodTrees gin.context 功能以及简单使用 功能: • 支持中间件操作&#xff08; handlersChain 机制 &#xff09; • 更方便的使用&#xff08; gin.Context &#xff09; • 更强大的路由解析能力&#xff08…

Web前端在深圳:探索技术与创新的融合之地

Web前端在深圳&#xff1a;探索技术与创新的融合之地 在数字化浪潮席卷全球的今天&#xff0c;深圳作为中国最具创新活力的城市之一&#xff0c;其在Web前端领域的发展同样引人注目。本文将从四个方面、五个方面、六个方面和七个方面&#xff0c;深入剖析深圳在Web前端领域的独…

Linux之tar打包解包命令

Linux之tar打包解包命令 打包与压缩区别 打包&#xff0c;也称之为归档&#xff0c;指的是一个文件或目录的集合&#xff0c;而这个集合被存储在一个文件中。归档文件没有经过压缩&#xff0c;所占空间是其中所有文件和目录的总和。 压缩&#xff0c;将一个大文件通过压缩算法…

基于 Delphi 的前后端分离:之五,使用 HTMX 让页面元素组件化之面向对象的Delphi代码封装

前情提要 本博客上一篇文章&#xff0c;描述了使用 Delphi 作为后端的 Web Server&#xff0c;前端使用 HTMX 框架&#xff0c;把一个开源的前端图表 JS 库&#xff0c;进行了组件化。 上一篇文章仅仅是描述了简单的前端代码组件化的可能性&#xff0c;依然是基于前端库的 JS…

windows下的eclipse按Ctrl+Shift+F格式化代码不起作用的处理

1、先上张图&#xff1a; 上面Format&#xff1a;CtrlShiftF&#xff0c;按了以后不起作用。 2、这个快捷键不起作用的原因&#xff1a;可能是快捷键冲突了。 机器上装了Sougou输入法&#xff0c;将输入法切换为英文模式是起作用的。 那么应该就是这个原因了。 3、解决方法…

【Ardiuno】使用ESP32单片机创建web服务通过网页控制小灯开关的实验(图文)

经过实验测试ESP32单片机的网络连接还是很方便的&#xff0c;这里小飞鱼按照程序实例的代码亲自实验一下使用Esp32生成的网页服务来实现远程无线控制小灯开关功能&#xff0c;这样真的是离物联网开发越来越近了&#xff0c;哈哈&#xff01; 连接好开发板和电路&#xff0c;将…

React入门教程:构建你的第一个React应用

在当今快速发展的Web开发领域&#xff0c;前端技术日新月异&#xff0c;而React作为一款强大的JavaScript库&#xff0c;已经成为众多开发者的首选。React以其组件化、高效的性能和灵活的数据处理机制闻名于世&#xff0c;被广泛用于构建动态且复杂的用户界面。在本教程中&…

Elixir学习笔记——输入输出和文件系统

本章介绍输入/输出机制、文件系统相关任务以及相关模块&#xff08;如 IO、File 和 Path&#xff09;。IO 系统提供了一个很好的机会来阐明 Elixir 和 Erlang VM 的一些思维模式和新奇思想。 输入输出模块 输入输出模块是 Elixir 中读写标准输入/输出 (:stdio)、标准错误 (:s…

vue学习(一)

1.vue是用于构建用户界面的渐进式js框架&#xff0c;自底向上逐层的应用&#xff1a; 简单应用&#xff1a;只需一个轻量小巧的核心库&#xff1b; 复杂应用&#xff1a;可以引入各式各样的vue插件&#xff1b; 2.vue特点&#xff1a; 采用组件化模式&#xff0c;提高代码复…

Python中关于电商商品数据的采集【taobao/JD/商品详情数据返回】

在Python中采集电商商品数据&#xff08;如淘宝、京东等&#xff09;通常涉及到网络爬虫&#xff08;web scraping&#xff09;或称为网络数据抓取&#xff08;web data scraping&#xff09;。由于电商平台通常会有反爬虫机制&#xff0c;因此直接抓取数据可能会遇到各种挑战&…

基于51单片机的智能水表

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