C++ 學習 多線程 2025年6月17日18:41:30

多線程(標準線程庫?<thread>)

創建線程

#include <iostream>
#include <thread>void hello() {std::cout << "Hello from thread!\n";
}int main() {// 創建線程并執行 hello() std::thread t(hello); //線程對象,傳入可調用對象(函數、Lambda、函數對象)t.join();              // 等待線程結束 阻塞主線程,直到子線程完成。
//t.detach():分離線程(線程獨立運行,主線程不等待)。
// 僅在明確不需要管理線程生命周期時使用 detach(),并確保資源安全。return 0;
}
傳遞參數(和平常函數調用不同 注意看):
void print_sum(int a, int b) {std::cout << a + b << "\n";
}int main() {std::thread t(print_sum, 10, 20);  // 傳遞參數t.join();
}
Lambda 表達式 線程:
std::thread t([] {std::cout << "Lambda thread\n";
});
t.join();

線程同步:

互斥鎖(Mutex):防止多個線程訪問 共享數據:
#include <mutex>std::mutex mtx;
int shared_data = 0;//原始手動加鎖 
void increment() {mtx.lock();          // 加鎖:如果其他線程已鎖,這里會阻塞等待shared_data++;       // 臨界區:唯一線程能執行的代碼mtx.unlock();        // 解鎖:允許其他線程進入
}
//風險:如果 shared_data++ 拋出異常,unlock() 可能不被執行,導致死鎖。void safe_increment() {std::lock_guard<std::mutex> lock(mtx);  // 構造時自動加鎖shared_data++;                          // 臨界區
} // 析構時自動解鎖(即使發生異常)
//RAII(資源獲取即初始化):利用對象生命周期自動管理鎖,避免忘記解鎖。加鎖后的正確流程
線程A加鎖 → shared_data++(變為1)→ 解鎖線程B加鎖 → shared_data++(變為2)→ 解鎖
結果:shared_data = 2。
高階用法:
void flexible_increment() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延遲加鎖// ...其他非臨界區代碼...lock.lock();       // 手動加鎖shared_data++;lock.unlock();     // 可手動提前解鎖
}=================================================//多個鎖時,按固定順序獲取:
std::mutex mtx1, mtx2;void safe_operation() {std::lock(mtx1, mtx2); // 同時加鎖(避免死鎖)std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);// 操作多個共享資源
}=============錯誤示范===============
int* get_data() {std::lock_guard<std::mutex> lock(mtx);return &shared_data; // ? 危險!鎖失效后仍可訪問
}注意事項
鎖粒度:鎖的范圍應盡量小(減少阻塞時間)。避免嵌套鎖:容易導致死鎖。不要返回鎖保護的指針/引用:會破壞封裝性。
線程之間通知機制 (條件變量)
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool data_ready = false;  // 條件變量依賴的共享狀態// 消費者線程(等待數據)
void consumer() {std::unique_lock<std::mutex> lock(mtx);std::cout << "消費者: 等待數據...\n";cv.wait(lock, [] { return data_ready; });  // 等待條件成立std::cout << "消費者: 收到數據,開始處理!\n";
}// 生產者線程(準備數據)
void producer() {std::this_thread::sleep_for(std::chrono::seconds(1));  // 模擬耗時操作{std::lock_guard<std::mutex> lock(mtx);data_ready = true;  // 修改共享狀態std::cout << "生產者: 數據已準備!\n";}cv.notify_one();  // 通知等待的消費者線程
}int main() {std::thread t1(consumer);  // 消費者線程(等待)std::thread t2(producer);  // 生產者線程(通知)t1.join();t2.join();return 0;
}//輸出效果 
消費者: 等待數據...
生產者: 數據已準備!
消費者: 收到數據,開始處理!關鍵點解析
條件變量 (std::condition_variable)用于線程間的條件同步,允許線程阻塞直到某個條件成立。必須與 std::mutex 和 一個共享狀態變量(如 bool data_ready)配合使用。
-------------------------------------------------------------------------
cv.wait(lock, predicate) 的工作原理步驟1:線程獲取鎖后檢查條件(predicate)。步驟2:若條件為 false,線程釋放鎖并進入阻塞狀態,等待通知。步驟3:當其他線程調用 notify_one() 時,線程被喚醒,重新獲取鎖并再次檢查條件。步驟4:若條件為 true,線程繼續執行;否則繼續等待。為什么需要 data_ready 變量?避免虛假喚醒:操作系統可能意外喚醒線程,因此需要顯式檢查條件。狀態同步:明確線程間的通信意圖(如“數據已準備好”)。鎖的作用域生產者:修改 data_ready 時必須加鎖(lock_guard)。消費者:wait() 會自動釋放鎖,喚醒后重新獲取鎖。

異步任務(得重點掌握):

std::async

異步執行函數,返回?std::future

#include <future>int compute() { return 42; }int main() {std::future<int> result = std::async(compute);std::cout << "Result: " << result.get() << "\n";  // 阻塞獲取結果
}std::launch::async:立即異步執行。std::launch::deferred:延遲到 get() 時執行。

=====================================================================

std::packaged_task

將函數包裝為可異步調用的任務:

std::packaged_task<int()> task([] { return 7 * 6; }); //異步包裝
std::future<int> result = task.get_future(); //future 用于稍后獲取異步結果。
std::thread t(std::move(task));  // 在線程中執行
t.join();
std::cout << "Result: " << result.get() << "\n";==================================================
通過 std::move:將 task 的所有權轉移給線程 t,避免拷貝。轉移后,原 task 對象變為 空狀態(不能再調用)

線程管理?

獲取硬件線程數:

std::thread::hardware_concurrency()

?返回的是?當前計算機硬件支持的線程并發數(通常等于邏輯CPU核心數)

線程不超過線程數時 效果最佳

unsigned cores = std::thread::hardware_concurrency();
std::cout << "CPU cores: " << cores << "\n";
//std::thread::hardware_concurrency() 返回的是 
//當前計算機硬件支持的線程并發數(通常等于邏輯CPU核心數)4 核 4 線程 CPU → 輸出 44 核 8 線程 CPU → 輸出 8蘋果 M1 Max (10 核) → 輸出 10
線程局部儲存(每個線程獨享的變量TLS):
thread_local int counter = 0;  // 每個線程有獨立副本

原子操作(無須鎖的安全操作)

為什么不需要鎖?

1.硬件支持

  • CPU 原子指令:現代 CPU 提供專門的指令(如 x86 的?LOCK XADD、ARM 的?LDREX/STREX)確保單條指令完成“讀取-修改-寫入”操作,不會被線程切換打斷。

  • 緩存一致性協議:通過 MESI 等協議保證多核間對原子變量的可見性。


2. 編譯器與語言標準保障

  • 編譯器屏障std::atomic?操作會阻止編譯器重排序相關指令。

  • 內存順序控制:支持靈活的內存序(如?memory_order_relaxedmemory_order_seq_cst),平衡性能與一致性需求。

#include <iostream>
#include <atomic>
#include <thread>std::atomic<int> counter(0);void increment(int n) {for (int i = 0; i < n; ++i) {counter++;  // 原子自增}
}int main() {std::thread t1(increment, 100000);std::thread t2(increment, 100000);t1.join(); t2.join();std::cout << "Counter: " << counter << "\n";  // 保證輸出 200000return 0;
}
特性std::atomicstd::mutex
實現層級硬件指令 + 編譯器優化操作系統級鎖(可能涉及系統調用)
粒度單個變量操作保護任意代碼塊
性能極高(無鎖設計)較高(存在鎖爭用開銷)
適用場景簡單變量(int、bool、指針等)復雜邏輯或跨多個變量的操作

?

std::atomic?的局限性
  • 僅適用于標量類型:對結構體等復雜類型需自定義或使用鎖。

  • 內存序選擇:錯誤的內存序可能導致意外行為(如?memory_order_relaxed?不保證順序)。

死鎖預防:

避免嵌套鎖:按固定順序加鎖。

使用?std::lock?同時鎖多個互斥量(前面互斥鎖有拓展)

std::mutex mtx1, mtx2;
std::lock(mtx1, mtx2);  // 同時加鎖(避免死鎖)
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);

線程池(運用第三方庫實現)廣泛應用于需要高并發處理短任務的場景(如HTTP服務器、并行計算等)

第三方庫(如?BS::thread_pool):
#include "thread_pool.hpp"          // 引入線程池庫頭文件
BS::thread_pool pool;              // 創建默認線程池(線程數=硬件并發數)
auto task = pool.submit([] { return 42; });  // 提交Lambda任務
std::cout << task.get() << "\n";   // 阻塞等待并獲取結果
BS::thread_pool線程池類,管理一組工作線程(通常數量=CPU核心數)。
pool.submit()提交任務(函數/Lambda)到線程池,返回?std::future?對象。
task.get()阻塞調用線程,直到任務完成并返回結果(類似?std::future::get)。

?

工作流程
  1. 線程池初始化

    • 創建時默認啟動?std::thread::hardware_concurrency()?個工作線程。

    • 線程空閑時會自動從任務隊列中取任務執行。

  2. 任務提交

    • submit?將 Lambda?[] { return 42; }?封裝為任務,放入隊列。

    • 返回的?task?是一個?std::future<int>,用于后續獲取結果。

  3. 結果獲取

    • task.get()?會阻塞主線程,直到某個工作線程完成該任務。

    • 最終輸出?42

對比原生?std::thread
特性BS::thread_poolstd::thread
線程管理自動復用線程(避免頻繁創建/銷毀)需手動管理線程生命周期
任務隊列支持批量提交任務需自行實現任務隊列
開銷低(線程復用)高(每次任務新建線程)
適用場景大量短任務少量長任務
?拓展用法示例:
//批量提交任務
std::vector<std::future<int>> results;
for (int i = 0; i < 10; ++i) {results.push_back(pool.submit([i] { return i * i; }));
}
for (auto& r : results) {std::cout << r.get() << " ";  // 輸出 0 1 4 9 16 25 36 49 64 81
}//獲取線程池信息
std::cout << "線程數: " << pool.get_thread_count() << "\n";//等待所有任務完成
pool.wait();  // 阻塞直到所有任務完成(不銷毀線程)

總結

功能工具頭文件
線程創建std::thread<thread>
互斥鎖std::mutex,?std::lock_guard<mutex>
條件變量std::condition_variable<condition_variable>
異步任務std::async,?std::future<future>
原子操作std::atomic<atomic>
線程局部存儲thread_local語言內置

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

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

相關文章

常見的測試工具及分類

Web測試工具是保障Web應用質量的核心支撐&#xff0c;根據測試類型&#xff08;功能、性能、安全、自動化等&#xff09;和場景需求&#xff0c;可分為多個類別。以下從??八大核心測試類型??出發&#xff0c;梳理常見工具及其特點、適用場景&#xff1a; ??一、功能測試工…

七牛存儲sdk在springboot完美集成和應用 七牛依賴 自動化配置

文章目錄 概要依賴配置屬性配置類配置文件業務層控制層運行結果亮點 概要 七牛存儲很便宜的&#xff0c;在使用項目的用好官方封裝好的sdk&#xff0c;結合springboot去使用很方便&#xff0c;我本地用的是springoot3spring-boot-autoconfigure 依賴 <dependency><…

Java相關-鏈表-設計鏈表-力扣707

你可以選擇使用單鏈表或者雙鏈表&#xff0c;設計并實現自己的鏈表。 單鏈表中的節點應該具備兩個屬性&#xff1a;val 和 next 。val 是當前節點的值&#xff0c;next 是指向下一個節點的指針/引用。 如果是雙向鏈表&#xff0c;則還需要屬性 prev 以指示鏈表中的上一個節點…

C# 關于LINQ語法和類型的使用

常用語法&#xff0c;具體問題具體分析 1. Select2. SelectMany3. Where4. Take5. TakeWhile6. SkipWhile7. Join8. GroupJoin9. OrderBy10. OrderByDescending11. ThenBy12. Concat13. Zip14. Distinct15. Except16. Union17. Intersect18. Concat19. Reverse20. SequenceEqua…

華為OD-2024年E卷-小明周末爬山[200分] -- python

問題描述&#xff1a; 題目描述 周末小明準備去爬山鍛煉&#xff0c;0代表平地&#xff0c;山的高度使用1到9來表示&#xff0c;小明每次爬山或下山高度只能相差k及k以內&#xff0c;每次只能上下左右一個方向上移動一格&#xff0c;小明從左上角(0,0)位置出發 輸入描述 第一行…

Android:使用OkHttp

1、權限&#xff1a; <uses-permission android:name"android.permission.INTERNET" /> implementation com.squareup.okhttp3:okhttp:3.4.1 2、GET&#xff1a; new XXXTask ().execute("http://192.168.191.128:9000/xx");private class XXXTask…

Vue3+Element Plus動態表格列寬設置

在 Vue3 Element Plus 中實現動態設置表格列寬&#xff0c;可以通過以下幾種方式實現&#xff1a; 方法 1&#xff1a;動態綁定 width 屬性&#xff08;推薦&#xff09; vue 復制 下載 <template><el-table :data"tableData" style"width: 100%…

【JVM目前使用過的參數總結】

JVM參數總結 筆記記錄 JVM-棧相關JVM-方法區(元空間)相關JVM-堆相關 JVM-棧相關 .-XX:ThreadStackSize1M -Xss1m 上面的簡寫形式【設置棧的大小】 JVM-方法區(元空間)相關 -XX:MaxMetaspaceSize10m 【設置最大元空間大小】 JVM-堆相關 -XX:MaxHeapSize10m -Xmx10m 上面的簡寫形…

AI輔助高考志愿填報-專業全景解析與報考指南

高考志愿填報&#xff0c;這可是關系到孩子未來的大事兒&#xff01;最近&#xff0c;我親戚家的孩子也面臨著這個難題&#xff0c;昨晚一個電話就跟我聊了好久&#xff0c;問我報啥專業好。說實話&#xff0c;這問題真不好回答&#xff0c;畢竟每個孩子情況不一樣&#xff0c;…

Android Studio Windows安裝與配置指南

Date: 2025-06-14 20:07:12 author: lijianzhan 內容簡介 文章中&#xff0c;主要是為了初次接觸 Android 開發的用戶提供詳細的關于 Android Studio 安裝以及配置教程&#xff0c;涵蓋環境準備、軟件下載、安裝配置全流程&#xff0c;重點解決路徑命名、組件選擇、工作空間設置…

SpringAI+DeepSeek-了解AI和大模型應用

一、認識AI 1.人工智能發展 AI&#xff0c;人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;使機器能夠像人類一樣思考、學習和解決問題的技術。 AI發展至今大概可以分為三個階段&#xff1a; 其中&#xff0c;深度學習領域的自然語言處理(Natural Lan…

IP5362至為芯支持無線充的22.5W雙C口雙向快充移動電源方案芯片

英集芯IP5362是一款應用于移動電源&#xff0c;充電寶&#xff0c;手機&#xff0c;平板電腦等支持無線充模式的22.5W雙向快充移動電源方案SOC芯片,集成同步升降壓轉換器、鋰電池充電管理、電池電量指示等功能。兼容全部快充協議&#xff0c;同步開關放電支持最大22.5W輸出功率…

手游剛開服就被攻擊怎么辦?如何防御DDoS?

手游新上線時遭遇DDoS攻擊是常見現象&#xff0c;可能導致服務器癱瘓、玩家流失甚至項目失敗。面對突如其來的攻擊&#xff0c;開發者與運營商需要迅速響應并建立長效防御機制。本文提供應急處理步驟與防御策略&#xff0c;助力游戲穩定運營。 一、手游開服遭攻擊的應急響應 快…

秋招是開發算法一起準備,還是只準備一個

THE LAST TIME 昨天晚上半夜有個星球的26屆的同學&#xff0c;私信問我。說目前是只準備開發還是開發算法一起準備&#xff08;兩者技術知識都挺欠缺的&#xff09; 看到這里&#xff0c;肯定有很多同學會說。馬上都該秋招了&#xff0c;還什么多線程開工&#xff0c;趕緊能住編…

web項目部署配置HTTPS遇到的問題解決方法

今天使用nginxtomcatssl完成了web項目的部署&#xff0c;本以為沒有什么問題&#xff0c;但是在頁面測試的時候又蹦出了這么一個問題&#xff0c;大致是說由于配置了HTTPS&#xff0c;但是之前的請求是通過HTTP請求的&#xff0c;所以現在被攔截&#xff0c;由于缺少某些權限信…

理解與建模彈性膜-AI云計算數值分析和代碼驗證

彈性膜在連接生物學理解和工程創新方面至關重要&#xff0c;因為它們能夠模擬軟組織力學、實現先進的細胞培養系統和促進柔性設備&#xff0c;廣泛應用于軟組織生物力學、細胞培養、生物膜建模和生物醫學工程等領域。 ??AI云計算數值分析和代碼驗證 彈性膜在連接生物學理解和…

AI大模型競賽升溫:百度發布文心大模型4.5和X1

AI大模型&#xff0c;作為智能技術的巔峰之作&#xff0c;正逐步改變著我們的生活與工作方式。近期&#xff0c;百度在AI大模型領域的最新動向&#xff0c;無疑為這場科技競賽再添一把火。3月16日&#xff0c;百度正式宣布發布文心大模型4.5及文心大模型X1&#xff0c;這兩款大…

升級OpenSSL和OpenSSH 修復漏洞

升級OpenSSL和OpenSSH 目前版本OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017 升級到OpenSSH_9.8p1, OpenSSL 1.1.1u 30 May 2023 服務器CentOS Linux release 7.6.1810 (Core) 一、升級OpenSSL到1.1.1u 下載并編譯 OpenSSL&#xff08;推薦目錄 /usr/local/openssl&…

JavaSE - Object 類詳細講解

定義 是所有類的直接或者間接父類&#xff0c;是 Java 中唯一一個沒有父類的類。其中所有的方法都是可以被子類繼承的。 常用方法 equals方法&#xff1a; 比較兩個對象引用的地址值是否相同&#xff0c;默認情況下是使用 “” 進行比較&#xff0c;但是這個方法一般會被之類…

觀遠ChatBI|讓數據分析像聊天一樣簡單

BI通過收集、整合和分析企業內部的各種數據&#xff0c;幫助企業發現數據中的模式和趨勢&#xff0c;從而做出更明智的商業決策&#xff0c;以此來提升企業的經營能力和競爭力。無論是傳統BI還是自助BI&#xff0c;都是為了在數據和人之間建立一座橋梁&#xff0c;使數據能夠被…