C++并發編程-2.C++ 線程管控

參考:https://llfc.club/category?catid=225RaiVNI8pFDD5L4m807g7ZwmF#!aid/2Tuk4RfvfBC788LlqnQrWiPiEGW

1. 簡歷

  • 本節介紹C++線程管控,包括移交線程的歸屬權,線程并發數量控制以及獲取線程id等基本操作。

2. 線程歸屬權

在這里插入圖片描述

  • 比如下面,我們說明了線程歸屬權的轉移方式
#include <iostream>
#include <thread>
#include <string>
void some_function()
{while (true){std::this_thread::sleep_for(std::chrono::seconds(1));}
}
void some_other_function()
{while (true){std::this_thread::sleep_for(std::chrono::seconds(1));}
}
int main()
{// t1 綁定some_functionstd::thread t1(some_function);// 2 轉移t1管理的線程給t2,轉移后t1無效std::thread t2 = std::move(t1);// 3 t1 可繼續綁定其他線程,執行some_other_functiont1 = std::thread(some_other_function);// 4  創建一個線程變量t3std::thread t3;// 5  轉移t2管理的線程給t3t3 = std::move(t2);// 6  轉移t3管理的線程給t1t1 = std::move(t3);std::this_thread::sleep_for(std::chrono::seconds(2000));return 0;
}

在這里插入圖片描述在這里插入圖片描述

3. joining_thread

joinable()

bool joinable() const noexcept;
在這里插入圖片描述
在這里插入圖片描述

  • 曾經有一份C++17標準的備選提案,主張引入新的類joining_thread,它與std::thread類似,但只要其執行析構函數,線程即能自動匯合,這點與scoped_thread非常像。可惜C++標準委員會未能達成共識,結果C++17標準沒有引入這個類,后來它改名為std::jthread,依然進入了C++20標準的議程(現已被正式納入C++20標準)。除去這些,實際上joining_thread類的代碼相對容易編寫
#include <iostream>
#include <thread>
#include <string>class joining_thread
{std::thread _t;public:joining_thread() noexcept = default;template <typename Callable, typename... Args>explicit joining_thread(Callable &&func, Args &&...args): _t(std::forward<Callable>(func), std::forward<Args>(args)...) {}explicit joining_thread(std::thread t) noexcept: _t(std::move(t)) {}joining_thread(joining_thread &&other) noexcept: _t(std::move(other._t)) {}joining_thread &operator=(joining_thread &&other) noexcept{// 如果當前線程可匯合,則匯合等待線程完成再賦值if (joinable()){join();}_t = std::move(other._t);return *this;}joining_thread &operator=(joining_thread other) noexcept{// 如果當前線程可匯合,則匯合等待線程完成再賦值if (joinable()){join();}_t = std::move(other._t);return *this;}~joining_thread() noexcept{if (joinable()){join();}}void swap(joining_thread &other) noexcept{_t.swap(other._t);}std::thread::id get_id() const noexcept{return _t.get_id();}bool joinable() const noexcept{return _t.joinable();}void join(){_t.join();}void detach(){_t.detach();}std::thread &as_thread() noexcept{return _t;}const std::thread &as_thread() const noexcept{return _t;}
};
  • 使用起來比較簡單,我們直接構造一個joining_thread對象即可。

在這里插入圖片描述
在這里插入圖片描述

4. 容器存儲

在這里插入圖片描述

void use_vector() {std::vector<std::thread> threads;for (unsigned i = 0; i < 10; ++i) {threads.emplace_back(param_function, i);}for (auto& entry : threads) {entry.join();}
}

5. 選擇運行數量

  • 借用C++標準庫的std::thread::hardware_concurrency()函數,它的返回值是一個指標,表示程序在各次運行中可真正并發的線程數量.我們可以模擬實現一個并行計算的功能,計算容器內所有元素的和
#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include<algorithm>
#include<numeric>template<typename lterator,typename T>
struct accumulate_block
{void operator()(lterator first, lterator last, T& result){result += std::accumulate(first, last, result);}
};template <typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{unsigned long const length = std::distance(first, last);if (!length)return init; // ?-- - ①  上面的代碼1處判斷要計算的容器內元素為0個則返回。unsigned long const min_per_thread = 25;unsigned long const max_threads =(length + min_per_thread - 1) / min_per_thread; // 等價于ceil(length / min_per_thread)  向上取整// ?-- - ② 2處計算最大開辟的線程數,我們預估每個線程計算25個數據長度。unsigned long const hardware_threads =std::thread::hardware_concurrency(); // 表示程序在各次運行中可真正并發的線程數量./*但是我們可以通過std::thread::hardware_concurrency返回cpu的核數,我們期待的是開辟的線程數小于等于cpu核數,這樣才不會造成線程過多時間片切換開銷。*/unsigned long const num_threads =std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); // ?-- - ③ 3處計算了適合開辟線程數的最小值。unsigned long const block_size = length / num_threads; // ?-- - ④ 4處計算了步長,根據步長移動迭代器然后開辟線程計算。std::vector<T> results(num_threads);std::vector<std::thread> threads(num_threads - 1); // ?-- - ⑤ 5處初始化了線程數-1個大小的vector,因為主線程也參與計算,所以這里-1.Iterator block_start = first;for (unsigned long i = 0; i < (num_threads - 1); ++i){ // 6處移動步長,7處開辟線程,8處更新起始位置。Iterator block_end = block_start;std::advance(block_end, block_size); // ?-- - ⑥// 定義在頭文件 <iterator> 中。它的作用是 將一個迭代器向前或向后移動指定的距離。threads[i] = std::thread( // ?-- - ⑦accumulate_block<Iterator, T>(),block_start, block_end, std::ref(results[i]));block_start = block_end; // ?-- - ⑧}accumulate_block<Iterator, T>()(block_start, last, results[num_threads - 1]); // ?-- - ⑨9處為主線程計算。for (auto& entry : threads)entry.join();                                             // ?-- - ⑩10 處讓所有線程joinreturn std::accumulate(results.begin(), results.end(), init); // ?-- - ? 11 處最后將所有計算結果再次調用std的accumulate算出結果。
}
void use_parallel_acc()
{std::vector<int> vec(1000000);for (int i = 0; i < 1000000; i++){vec.push_back(i);}int sum = 0;sum = parallel_accumulate<std::vector<int>::iterator, int>(vec.begin(),vec.end(), sum);std::cout << "sum is " << sum << std::endl;
}int main()
{use_parallel_acc();return 0;
}

6. 識別線程

所謂識別線程就是獲取線程id,可以根據線程id是否相同判斷是否同一個線程。比如我們啟動了一個線程,我們可以通過線程變量的get_id()獲取線程id。

std::thread t([](){std::cout << "thread start" << std::endl;
});
t.get_id();
  • 但是如果我們想在線程的運行函數中區分線程,或者判斷哪些是主線程或者子線程,可以通過這總方式

std::thread t([](){std::cout << "in thread id " << std::this_thread::get_id() << std::endl;std::cout << "thread start" << std::endl;
});

std::this_thread::get_id()
t.get_id()

7. 總結

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87248.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87248.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87248.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Qt面試常問

1.QT信號與槽的底層原理&#xff1f; 底層通過元對象系統和事件循環完成的&#xff0c;能夠在運行期間動態處理信號槽之間的連接與斷開&#xff0c;而不是像函數調用那樣在編譯期間就完全確定了。元對象系統包含&#xff1a;QObject類、Q_OBJECT宏定義、moc編譯器當發送一個信…

【git】錯誤

【成功解決】開代理 unable to access ‘https://github.com/laigeoffer/pmhub.git/’: Recv failure: Connection was reset

什么是狀態機?狀態機入門

狀態機&#xff1a;優雅管理復雜邏輯的Python實踐 在軟件開發中&#xff0c;狀態機&#xff08;Finite State Machine, FSM&#xff09; 是管理多狀態轉換的利器。它將行為分解為離散的狀態、事件和轉移規則&#xff0c;大幅提升代碼的可讀性與可維護性。本文通過Python示例解析…

【Python打卡Day41】簡單CNN@浙大疏錦行

可以看到即使在深度神經網絡情況下&#xff0c;準確率仍舊較差&#xff0c;這是因為特征沒有被有效提取----真正重要的是特征的提取和加工過程。MLP把所有的像素全部展平了&#xff08;這是全局的信息&#xff09;&#xff0c;無法布置到局部的信息&#xff0c;所以引入了卷積神…

MySQL中InnoDB存儲引擎底層原理與MySQL日志機制深入解析

MySQL的內部組件結構如下&#xff1a; 大體來說&#xff0c;MySQL 可以分為 Server 層和存儲引擎層兩部分。 Server層 主要包括連接器、查詢緩存、分析器、優化器、執行器等&#xff0c;涵蓋 MySQL 的大多數核心服務功能&#xff0c;以及所有的內置函數&#xff08;如日期、…

MCP基本概念

基本概念 現在大模型交互的熱門形式&#xff1a; 第一、Agent與Tools(工具)的交互Agent需要調用外部工具和APl、訪問數據庫、執行代碼等。> MCP 第二、Agent與Agent(其他智能體或用戶)的交互Agent需要理解其他Agent的意圖、協同完成任務、與用戶進行自然的對話。 > A2A…

Docker容器相關命令介紹和示例

Docker 容器是鏡像的運行實例。以下是常用的 Docker 容器命令及其示例&#xff1a; 1. 運行容器 docker run [選項] <鏡像名> [命令]常用選項&#xff1a; -d&#xff1a;后臺運行&#xff08;守護模式&#xff09;-it&#xff1a;交互式終端--name&#xff1a;指定容…

【Akshare】高效下載股票和ETF數據

在量化投資與金融數據分析的世界里&#xff0c;獲取高質量的市場數據是構建有效策略的關鍵。Python庫Akshare為我們提供了一個強大且易于使用的接口&#xff0c;可以輕松地從網絡上抓取各類金融數據。本文將詳細介紹如何利用Akshare下載股票和ETF的歷史行情數據。 安裝Akshare…

分布式--3--分布式事務

1 簡介 事務在單系統中的表現&#xff1a;多次數據庫操作用事務進行管理&#xff0c;來保證ACID原則。 但是如果各個模塊都是單獨獨立出來的微服務&#xff0c;進行了分布式部署&#xff0c;單系統里的事務將不能保證各個數據庫操作的一致性&#xff0c;因此就需要分布式事務來…

不同建模方式的介紹 RTL建模筆記(1)

說明&#xff1a;該專欄"RTL建模筆記"是《RTL Modeling with SystemVerilog for Simulation and Synthesis》的翻譯&#xff1b;該筆記略過了第一章第一小節中背景介紹內容&#xff0c;以及第二小節前面部分的門級、RTL級建模介紹&#xff0c;對于后續學習不影響。 …

<13>-MySQL用戶管理

目錄 一&#xff0c;用戶管理操作 1&#xff0c;創建用戶 2&#xff0c;查詢用戶 3&#xff0c;修改密碼 4&#xff0c;刪除用戶 二&#xff0c;數據庫權限 1&#xff0c;用戶授權 2&#xff0c;回收權限 一&#xff0c;用戶管理操作 1&#xff0c;創建用戶 --創建用戶…

如何使用超低噪聲電源提高AD 時鐘電路質量,改善超聲系統的圖像質量

超聲波技術是醫療診斷和其他應用中廣泛使用的無創工具&#xff0c;已經從靜態圖像進化到動態圖像&#xff0c;從黑白呈現變為彩色多普勒圖像。這些重大進步主要是由于引入了數字超聲技術。雖然這些進步提高了超聲成像的有效性和通用性&#xff0c;但同樣重要的是&#xff0c;這…

【解決方案】Kali 2022.3修復倉庫密鑰一鍵安裝docker,docker compose

1、Kali 2022.3 2、一鍵安裝docker&#xff0c;docker compose #!/bin/bashecho " 安全的Kali Docker安裝腳本 "# 備份重要配置 cp /etc/apt/sources.list /etc/apt/sources.list.backup.$(date %Y%m%d)# 修復Kali倉庫配置 echo "修復Kali倉庫配置..." ca…

Transformer、RNN (循環神經網絡) 和 CNN (卷積神經網絡)的區別

我們來詳細對比一下 Transformer、RNN (循環神經網絡) 和 CNN (卷積神經網絡) 這三種在深度學習中極其重要的架構&#xff0c;并通過具體例子說明它們的區別。 核心區別總結&#xff1a; 處理數據的方式&#xff1a; CNN: 專注于局部特征和空間/時間模式。通過卷積核在輸入數據…

408第二季 - 組成原理 - 數據類型轉換

這章內容會比較少 閑聊 如果題目說把8位改成4位&#xff0c;你保留低位就行了 這里保留的是0101 然后是有符號數和無符號數的轉換 機器數就是二進制長什么樣子 然后就是小數點是不參與存儲的 然后簡單看看代碼 這是short就說明是有符號數 unsigned就是說明是無符號數 然后y…

讓 Deepseek 寫電器電費計算器(html版本)

以下是一個簡單的電器電費計算器的HTML和CSS代碼&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…

react_flow自定義節點、邊——使用darg布局樹狀結構

文章目錄 ?前言?引入react-flow?自定義節點nodeType?自定義邊edgeType?添加節點?inscode代碼塊?結束 ?前言 大家好&#xff0c;我是yma16&#xff0c;本文分享 前端 ——react_flow自定義節點、邊——使用darg布局樹狀結構。 自定義效果 可以自定義節點、邊、線條流動…

word表格批量轉excel,提取表格數據到excel

本文將帶你一步步實現一個將 Word 中的表格內容批量提取并轉換為 Excel 文件的自動化工具&#xff0c;適用于需要手動復制粘貼數據到excel的場景 假設我們有這樣的表格在word中&#xff0c;圖片世放在excel中便于截圖&#xff0c;現在需要將表格中有顏色的數據提取到對應的exce…

day2課程

1.添加pinia到Vue項目 2.counter基礎使用 3.getters和異步action 4.storeToRefs和調試 5.項目初始化和git管理 6.別名路徑聯想設置 7.elementsPlus自動按需導入配置 這個項目使用的是按需引入 1.安裝包管理器 npm install element-plus --save 2.按需引入 npm install -D unp…

Vue3 + TypeScript + Element Plus 設置表格行背景顏色

技術要點&#xff1a; 1、使用 :row-class-name"setRowClassName" 設置表格行類名 2、不能同時使用 stripe 3、設置行類名的樣式 應用效果&#xff1a; 同時使用 stripe 出來的效果&#xff1a; 參考代碼&#xff1a; ReagentTable.vue <script setup lang&…