C++标准线程库实现优雅退出的方式

目录

1.通过设置共享退出标记

2.使用std::jthread创建线程

3.定义消息类型的方式

4.注意事项


1.通过设置共享退出标记

        定义一个退出变量bool stop = false; 表示线程是否应该停止。在主线程中设置标记stop=true,然后join一直等待,然后线程循环检测到stop是否为true,为true则表示线程该退出了。示例代码如下:

IThread.h

#ifndef  _I_THREAD_H_
#define  _I_THREAD_H_
#include "LinkGlobal.h"
#include <Thread>
#include <memory>LINK_CORE_NAMESPACE_BEGINclass IThread
{
public:explicit IThread();virtual ~IThread() = default;public:void start();void join();protected:virtual void run() = 0;private:std::unique_ptr<std::thread> m_thread;bool m_bStarted;
};LINK_CORE_NAMESPACE_END#endif

IThread.cpp

#include "IThread.h"LINK_CORE_NAMESPACE_BEGINIThread::IThread():m_bStarted(false), m_thread(nullptr)
{}void IThread::start()
{if (m_bStarted) {join();return;}m_thread.reset(new std::thread(&IThread::run, this));m_bStarted = true;
}void IThread::join()
{if (m_bStarted && m_thread) {if (m_thread->joinable()) {m_thread->join();}}m_bStarted = false;
}LINK_CORE_NAMESPACE_END

QueryDataCmdThread.h

#pragma once
#include "IThread.h"
#include "DataType.h"
#include <string>
#include <QByteArray>
using namespace xyLinkCore;class CQueryDataCmdThread : public IThread
{
public:CQueryDataCmdThread (PUInt64 chaissID, PUInt64 signalID);virtual ~CQueryDataCmdThread ();public:int start();int stop();private:void  run() override;void  sendQueryCmd();void  encodeData();private:bool   m_bStop;PUInt64 m_chaissID;PUInt64 m_signalID;bool   m_status;std::string m_waveName;QByteArray  m_data;
};

QueryDataCmdThread.cpp

#include "QueryDataCmdThread.h"
#include "HardwareDataProcCenter.h"CQueryDataCmdThread::CQueryDataCmdThread(PUInt64 chaissID, PUInt64 signalID): m_bStop(false), m_chaissID(chaissID), m_signalID(signalID), m_status(false)
{encodeData();
}CQueryDataCmdThread::~CQueryDataCmdThread()
{stop();
}int CQueryDataCmdThread::start()
{m_bStop = false;m_status = false;IThread::start();return 1;
}
int CTTNTQueryDataCmdThread::stop()
{if (m_status) {return 1;}m_bStop = true;IThread::join();return 1;
}void CQueryDataCmdThread::run()
{while (true) {//[1]if (m_bStop) {m_status = true;break;}//[2]sendQueryCmd();//[3]std::this_thread::sleep_for(std::chrono::milliseconds(200));}
}void  CQueryDataCmdThread::encodeData()
{//...
}void  CTTNTQueryDataCmdThread::sendQueryCmd()
{//...
}

2.使用std::jthread创建线程

        std::jthread 是 C++20 标准库中引入的一个新特性,它代表了一个可加入的线程(joinable thread),它确保了线程在其生命周期内始终运行一个特定的任务(即一个函数对象、lambda 表达式或者可调用对象)。std::jthread 的设计旨在简化多线程编程中的一些常见模式,特别是那些需要确保线程在其生命周期内始终运行的任务。

  std::jthread std::thread 基础上,增加了能够主动取消或停止线程执行的新特性。与 std::thread 相比,std::jthread 具有异常安全的线程终止流程,并且在大多数情况下可以替换它,只需很少或无需更改代码。

        示例代码如下:

#include <iostream>
#include <chrono>
#include <thread>// 使用 std::jthread 运行的函数
void task(std::stop_token stoken) {while (!stoken.stop_requested()) {std::cout << "任务正在运行..." << std::endl;// 模拟一些工作std::this_thread::sleep_for(std::chrono::seconds(1));}std::cout << "任务已收到停止请求,现在停止运行。" << std::endl;
}int main() {// 创建 std::jthread,自动处理停止令牌std::jthread worker(task);// 模拟主线程运行一段时间后需要停止子线程std::this_thread::sleep_for(std::chrono::seconds(5));std::cout << "主线程请求停止子线程..." << std::endl;// 触发停止请求worker.request_stop();// std::jthread 在析构时自动加入return 0;
}

有了std::thread,为什么还需要引入std::jthread?-CSDN博客

3.定义消息类型的方式

spdlog一个非常好用的C++日志库(五): 源码分析之线程池thread_pool_spdlog源码分析-CSDN博客

        在spdlog的线程池thread_pool源码分析一文中,首先定义了消息类型:

enum class async_msg_type
{log,           //普通日志消息flush,         //冲刷日志消息到目标(sink)terminate      //终止线程池子线程(工作线程)
};

接下来就是在thread_pool的析构函数出提交一条async_msg_type::terminate消息,如下面代码:

SPDLOG_INLINE thread_pool::~thread_pool()
{// 析构函数不要抛出异常, 但释放线程池资源资源可能发生异常, 因此内部捕获并处理SPDLOG_TRY{for (size_t i = 0; i < threads_.size(); i++) {// terminate thread looppost_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);}for (auto & t : threads_) {t.join();}}SPDLOG_CATCH_STD
}

最后在单个线程循环中,检测到async_msg_type::terminate消息,就退出线程,代码如下:

// 子线程循环
void SPDLOG_INLINE thread_pool::worker_loop_() 
{while (process_next_msg_()) {}
}// process next message in the queue
// return true if this thread should still be active (while no terminate msg
// was received)
bool SPDLOG_INLINE thread_pool::process_next_msg_()
{async_msg incoming_async_msg;bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10)); // 从环形缓冲区取出数据if (!dequeued){return true;}// 成功取出一条数据存作为异步消息, 根据消息类型分类处理switch (incoming_async_msg.msg_type){case async_msg_type::log: {       // 处理类别为log的异步消息incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg);return true;}case async_msg_type::flush: {     // 处理类别为flush的异步消息incoming_async_msg.worker_ptr->backend_flush_();return true;}case async_msg_type::terminate: { // 处理类别为terminate的异步消息return false;}default: {assert(false); // impossible except exception}}return true;
}

4.注意事项

  • 确保在发送停止信号后,主线程等待工作线程实际退出(使用joindetach,但通常使用join以确保资源被正确释放)。
  • 在线程函数内部,确保在退出前释放所有分配的资源,包括动态内存、文件句柄、网络连接等。
  • 避免在多个线程之间共享可变数据,除非使用了适当的同步机制(如互斥锁、读写锁等)。

通过上述方法,你可以实现C++标准线程库中的线程优雅退出。

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

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

相关文章

Java学习教程,从入门到精通,JDBC插入记录语法及案例(104)

JDBC插入记录语法及案例 一、JDBC插入记录语法 在JDBC中&#xff0c;插入记录主要通过执行SQL的INSERT语句来实现。其基本语法如下&#xff1a; INSERT INTO 表名 (列1, 列2, ..., 列n) VALUES (值1, 值2, ..., 值n);表名&#xff1a;需要插入记录的表的名称。列1, 列2, …,…

vue事件总线(原理、优缺点)

目录 一、原理二、使用方法三、优缺点优点缺点 四、使用注意事项具体代码参考&#xff1a; 一、原理 在Vue中&#xff0c;事件总线&#xff08;Event Bus&#xff09;是一种可实现任意组件间通信的通信方式。 要实现这个功能必须满足两点要求&#xff1a; &#xff08;1&#…

图像处理之HSV颜色空间

目录 1 RGB 的局限性 2 HSV 颜色空间 3 RGB与HSV相互转换 4 HSV颜色模型对图像的色相、饱和度和明度进行调节 5 演示Demo 5.1 开发环境 5.2 功能介绍 5.3 下载地址 参考 1 RGB 的局限性 RGB 是我们接触最多的颜色空间&#xff0c;由三个通道表示一幅图像&#xff0c;分…

DeepSeek是由杭州深度求索人工智能基础技术研究有限公司(简称“深度求索”)发布的一系列人工智能模型

DeepSeek是由杭州深度求索人工智能基础技术研究有限公司&#xff08;简称“深度求索”&#xff09;发布的一系列人工智能模型&#xff0c;其在知识类任务上展现出了卓越的性能。以下是对DeepSeek的详细介绍&#xff0c;内容虽无法达到10000字&#xff0c;但会尽可能全面且深入地…

【C++高并发服务器WebServer】-9:多线程开发

本文目录 一、线程概述1.1 线程和进程的区别1.2 线程之间共享和非共享资源1.3 NPTL 二、线程操作2.1 pthread_create2.2 pthread_exit2.3 pthread_join2.4 pthread_detach2.5 patch_cancel2.6 pthread_attr 三、实战demo四、线程同步五、死锁六、读写锁七、生产消费者模型 一、…

14-6-1C++STL的list

(一&#xff09;list容器的基本概念 list容器简介&#xff1a; 1.list是一个双向链表容器&#xff0c;可高效地进行插入删除元素 2.list不可以随机存取元素&#xff0c;所以不支持at.(pos)函数与[ ]操作符 &#xff08;二&#xff09;list容器头部和尾部的操作 list对象的默…

在sortablejs的拖拽排序情况下阻止input拖拽事件

如题 问题 在vue3的elementPlus的table中&#xff0c;通过sortablejs添加了行拖拽功能&#xff0c;但是在行内会有输入框&#xff0c;此时拖拽输入框会触发sortablejs的拖拽功能 解决 基于这个现象&#xff0c;我怀疑是由于拖拽事件未绑定而冒泡到后面的行上从而导致的拖拽…

21.Word:小赵-毕业论文排版❗【39】

目录 题目​ NO1.2 NO3.4 NO5.6 NO7.8.9 NO10.11.12 题目 NO1.2 自己的论文当中接收老师的修改&#xff1a;审阅→比较→源文档&#xff1a;考生文件夹&#xff1a;Word.docx→修订的文档&#xff1a;考生文件夹&#xff1a;教师修改→确定→接收→接收所有修订将合并之…

leetcode_链表 876.链表的中间节点

876.链表的中间节点 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。如果有两个中间结点&#xff0c;则返回第二个中间结点。思路&#xff1a;快慢指针&#xff0c;创建两个指针fast和slow&#xff0c;fast指针每次移动两步&#xff0c;slow指针每次移动…

深度学习 DAY3:NLP发展史及早期的前馈神经网络(ANN)及多任务学习

NLP发展史 NLP发展脉络简要梳理如下&#xff1a; 2001 - Neural language models&#xff08;神经语言模型&#xff09; 2008 - Multi-task learning&#xff08;多任务学习&#xff09; 2013 - Word embeddings&#xff08;词嵌入&#xff09; 2013 - Neural networks for NL…

全面了解 Web3 AIGC 和 AI Agent 的创新先锋 MelodAI

不管是在传统领域还是 Crypto&#xff0c;AI 都是公认的最有前景的赛道。随着数字内容需求的爆炸式增长和技术的快速迭代&#xff0c;Web3 AIGC&#xff08;AI生成内容&#xff09;和 AI Agent&#xff08;人工智能代理&#xff09;正成为两大关键赛道。 AIGC 通过 AI 技术生成…

54.数字翻译成字符串的可能性|Marscode AI刷题

1.题目 问题描述 小M获得了一个任务&#xff0c;需要将数字翻译成字符串。翻译规则是&#xff1a;0对应"a"&#xff0c;1对应"b"&#xff0c;依此类推直到25对应"z"。一个数字可能有多种翻译方法。小M需要一个程序来计算一个数字有多少种不同的…

FileReader使用

FileReader : 读取文件内容的api&#xff0c;&#xff0c;&#xff0c;在前端处理上传的文件&#xff0c;&#xff0c;比如预览图片 readAsDataURL(file) &#xff1a; 读取为base64编码的 data urlreadAsText() &#xff1a; 读取为文本readAsArrayBuffer() : 读取为二进制 …

RabbitMQ5-死信队列

目录 死信的概念 死信的来源 死信实战 死信之TTl 死信之最大长度 死信之消息被拒 死信的概念 死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;一般来说&#xff0c;producer 将消息投递到 broker 或直接到queue 里了&#xff0c;consumer 从 queue 取出消息进…

JavaScript系列(48)-- 3D渲染引擎实现详解

JavaScript 3D渲染引擎实现详解 &#x1f3ae; 今天&#xff0c;让我们深入探讨JavaScript的3D渲染引擎实现。通过WebGL和现代JavaScript技术&#xff0c;我们可以构建一个功能完整的3D渲染系统。 3D渲染基础概念 &#x1f31f; &#x1f4a1; 小知识&#xff1a;3D渲染引擎的…

10JavaWeb——SpringBootWeb案例01

前面我们已经讲解了Web前端开发的基础知识&#xff0c;也讲解了Web后端开发的基础(HTTP协议、请求响应)&#xff0c;并且也讲解了数据库MySQL&#xff0c;以及通过Mybatis框架如何来完成数据库的基本操作。 那接下来&#xff0c;我们就通过一个案例&#xff0c;来将前端开发、后…

【面试题】 Java 三年工作经验(2025)

问题列表 为什么选择 spring boot 框架&#xff0c;它与 Spring 有什么区别&#xff1f;spring mvc 的执行流程是什么&#xff1f;如何实现 spring 的 IOC 过程&#xff0c;会用到什么技术&#xff1f;spring boot 的自动化配置的原理是什么&#xff1f;如何理解 spring boot 中…

JAVA 接口、抽象类的关系和用处 详细解析

接口 - Java教程 - 廖雪峰的官方网站 一个 抽象类 如果实现了一个接口&#xff0c;可以只选择实现接口中的 部分方法&#xff08;所有的方法都要有&#xff0c;可以一部分已经写具体&#xff0c;另一部分继续保留抽象&#xff09;&#xff0c;原因在于&#xff1a; 抽象类本身…

ResNeSt: Split-Attention Networks论文学习笔记

这张图展示了一个名为“Split-Attention”的神经网络结构&#xff0c;该结构在一个基数组&#xff08;cardinal group&#xff09;内进行操作。基数组通常指的是在神经网络中处理的一组特征或通道。图中展示了如何通过一系列操作来实现对输入特征的注意力机制。 以下是图中各部…

数据收集后台服务概要设计

为了帮助大家设计一个数据指标汇总的后端应用&#xff0c;我将提供一个概要设计和表设计的建议。这个设计将基于常见的数据收集需求&#xff0c;假设你需要收集、存储和汇总来自不同数据源的指标数据。 1. 概要设计 1.1 系统架构 数据收集层&#xff1a;负责从不同数据源&am…