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.pswp.cn/web/67326.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/67326.shtml
英文地址,請注明出處:http://en.pswp.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…