C++ 多線程實戰 10|C++20 的信號量、閂鎖與屏障

目錄

前言

學習目標

1. 信號量(Semaphore)

示例:限制并發下載任務

2. 閂鎖(Latch)

示例:賽跑

3. 屏障(Barrier)

示例:圖像處理流水線

4. 常見坑與對策

5. 實踐作業

總結


前言

有時候寫多線程代碼,會感覺自己像個“交通警察”:

  • 這里要限流,不能讓大家一擁而上;

  • 那里要等所有人到齊,才能一起發車;

  • 還有時候要分階段執行,上一階段沒完,下一階段不能亂跑。

C++20 就給我們準備了三個“神器”:信號量(semaphore)、閂鎖(latch)和屏障(barrier)。它們比 mutexcondition_variable 更貼近并發算法的實際需求。今天我們就一起來拆解這三個工具。


學習目標

  1. 理解 信號量:限制并發數量的計數器。

  2. 理解 閂鎖:一次性同步點(大家到齊再走)。

  3. 理解 屏障:可重用的多階段同步工具。

  4. 掌握在實際場景中如何選擇正確的同步原語。


1. 信號量(Semaphore)

信號量其實很古老了,操作系統里早就有。它的直覺含義就是:有多少個“通行證”

  • std::counting_semaphore<N>:計數信號量,最多 N 張通行證。

  • std::binary_semaphore:只有 0 和 1,相當于一個簡單開關。

工作原理:

  • acquire():拿一張票。如果沒有票,就等待。

  • release():放回一張票,別人可以用。

示例:限制并發下載任務

假設我們要同時下載 3 個文件,超過 3 個要排隊。

#include <iostream>
#include <thread>
#include <semaphore>
#include <vector>
#include <chrono>
using namespace std;counting_semaphore<3> sem(3); // 最多允許 3 個并發任務void download(int id) {sem.acquire(); // 拿到“許可證”cout << "線程 " << id << " 開始下載..." << endl;this_thread::sleep_for(chrono::seconds(2));cout << "線程 " << id << " 下載完成!" << endl;sem.release(); // 歸還“許可證”
}int main() {vector<thread> threads;for (int i = 0; i < 10; ++i)threads.emplace_back(download, i);for (auto &t : threads) t.join();
}

運行結果:同時只有 3 個任務在下載,其他線程排隊等待。
是不是就像“廁所蹲位有限,來晚了的同學只能等著”?😂


2. 閂鎖(Latch)

閂鎖就是“一次性的大門”:大家必須等到所有人都到齊,才能一起開門進入下一階段

  • std::latch 只能用一次(單次同步點)。

  • 常見場景:多個線程并行準備,等所有人準備好后,一起開始執行。

示例:賽跑

#include <iostream>
#include <thread>
#include <latch>
#include <vector>
using namespace std;latch start_line(3); // 等待 3 個選手void runner(int id) {cout << "運動員 " << id << " 就位" << endl;start_line.arrive_and_wait(); // 到齊才出發cout << "運動員 " << id << " 開跑!" << endl;
}int main() {vector<thread> threads;for (int i = 0; i < 3; ++i)threads.emplace_back(runner, i);for (auto &t : threads) t.join();
}

運行結果:所有運動員就位之后,才一起開跑。


3. 屏障(Barrier)

屏障就像閂鎖的“可重復版”。

  • std::barrier 支持 多輪同步

  • 每一輪,所有線程必須到齊,才能進入下一輪。

  • 還可以在每一輪結束時執行一個“階段完成回調”。

示例:圖像處理流水線

我們有三張圖片,每張要經過三輪處理(預處理 → 濾鏡 → 保存)。

#include <iostream>
#include <thread>
#include <barrier>
#include <vector>
using namespace std;void process(int id, barrier<> &bar) {for (int stage = 1; stage <= 3; ++stage) {cout << "線程 " << id << " 執行第 " << stage << " 階段" << endl;bar.arrive_and_wait(); // 等所有人完成這個階段}
}int main() {barrier bar(3, []{ cout << "=== 一個階段完成 ===" << endl; });vector<thread> threads;for (int i = 0; i < 3; ++i)threads.emplace_back(process, i, ref(bar));for (auto &t : threads) t.join();
}

運行效果:

  • 每個階段,所有線程都要等齊;

  • 每輪結束,打印“階段完成”。

這就像三個人組隊打副本,必須等大家都打完當前關卡,才能進入下一關。


4. 常見坑與對策

工具常見坑對策
信號量release() 次數和 acquire() 不匹配,導致線程永遠卡住或無限放行保持配對,最好寫成 RAII 封裝
閂鎖只能用一次,用完不能重置多階段場景請用 barrier
屏障回調函數里阻塞,導致死鎖回調必須盡快返回,不要做耗時操作

5. 實踐作業

  1. 修改“下載任務”的例子,把 counting_semaphore 改為 binary_semaphore,看看效果有什么不同。

  2. latch 實現一個“多人開會”,所有人到齊后一起進入會議。

  3. barrier 寫一個分階段矩陣運算程序,驗證每一階段都同步完成。


總結

今天我們學習了 C++20 的三大同步原語:

  • 信號量:控制并發數量,就像限流閥門。

  • 閂鎖:一次性同步點,大家到齊一起走。

  • 屏障:可重用的多階段同步工具,常用于分階段算法。

它們比傳統的 mutex + condition_variable 更直觀,也更貼近實際并發場景。掌握好這三大工具,你就能寫出更優雅的并發代碼。

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

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

相關文章

【Java SE】01. 初識Java

1. 認識Java Java是一種優秀的程序設計語言&#xff0c;它具有令人賞心悅目的語法和易于理解的語義。Java還是一個有一系列計算機軟件和規范形成的技術體系&#xff0c;這個技術體系提供了完整的用于軟件開發和跨平臺部署的支持環境&#xff0c;并廣泛應用于嵌入式系統、移動終…

解鎖倉儲智能調度、運輸路徑優化、數據實時追蹤,全功能降本提效的智慧物流開源了

AI 視頻監控平臺&#xff1a;全鏈路協同驅動的智能監控解決方案AI 視頻監控平臺是一款融合高性能功能與輕量化操作的實時算法驅動型視頻監控系統&#xff0c;其核心愿景在于深度破除不同芯片廠商間的技術壁壘&#xff0c;省去冗余重復的適配環節&#xff0c;最終達成芯片、算法…

冒泡排序與選擇排序以及單鏈表與雙鏈表

1. 冒泡排序&#xff08;Bubble Sort&#xff09; 1. 原理 冒泡排序是一種 簡單的排序算法&#xff0c;通過 兩兩比較相鄰元素&#xff0c;把較大的元素逐漸 “冒泡” 到數組末尾。 思路&#xff1a; 從數組頭開始&#xff0c;比較相鄰兩個元素。 如果前一個比后一個大&…

Python實現計算點云投影面積

本次我們分享一種基于 Open3D 的快速、穩健方法&#xff0c;用于從激光點云中自動提取“地面”并計算其投影面積。算法先自適應估計地面高程&#xff0c;再將地面點投影至水平面&#xff0c;隨后用凸包或最小外接矩形求取面積。整個流程無需人工干預&#xff0c;單文件即可運行…

AXI4 協議

一、AXI4簡介AXI4&#xff08;Advanced eXtensible Interface 4&#xff09;是ARM公司推出的高性能片上總線協議&#xff0c;屬于AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09;標準的一部分。它專為高帶寬、低延遲的片上通信設計&#xff0c;廣泛應用…

《餓殍:明末千里行》Switch版試玩發布 3月13日發售

使用jQuery的常用方法與返回值分析 jQuery是一個輕量級的JavaScript庫&#xff0c;旨在簡化HTML文檔遍歷和操作、事件處理以及動畫效果的創建。本文將介紹一些常用的jQuery方法及其返回值&#xff0c;幫助開發者更好地理解和運用這一強大的庫。 1. 選擇器方法 jQuery提供了多種…

[特殊字符] 認識用戶手冊用戶手冊(也稱用戶指南、產品手冊)是通過對產品功能的清

一份優秀的用戶手冊能有效降低用戶的使用門檻&#xff0c;提升用戶體驗和工作效率。下面我將為你梳理編寫用戶手冊的核心要點、步驟和技巧。&#x1f4d6; 認識用戶手冊用戶手冊&#xff08;也稱用戶指南、產品手冊&#xff09;是??通過對產品功能的清晰解釋&#xff0c;為特…

蘋果軟件代碼混淆,iOS混淆、iOS加固、ipa安全與合規取證注意事項(實戰指南)

在移動軟件交付與合規審計中&#xff0c;蘋果軟件代碼混淆已成為保護知識產權與用戶數據的常規手段。但混淆帶來的不僅是逆向難度的提升&#xff0c;也會觸發崩潰取證、符號化&#xff08;symbolication&#xff09;、審計合規與法律證據保存等問題。本文從工程與合規雙視角出發…

Redis框架詳解

目錄 1. redis是什么 主要特點 2. redis中存儲的數據類型 2.1 String類型 2.2 List類型 2.3 Hash類型 2.4 Set類型 2.5 Zset類型 2.6 其它類型 3.redis高可用框架 1. redis是什么 Redis 是一個開源的、基于內存的數據結構存儲系統&#xff0c;是 Remote Dictionary…

每日隨機展示10個wordpress置頂文章

WordPress 置頂文章是博主根據自己的需要設置的&#xff0c;通常用于展示重要或熱門的文章。 以下是一個示例代碼&#xff0c;用于在 WordPress 主題中展示 10 個置頂文章&#xff1a; <?php // 查詢置頂文章 $sticky get_option(sticky_posts); $args array(post__in …

金融工程vs金融數學:誰更貼近量化交易?

在金融行業邁向高度數字化的今天&#xff0c;量化交易已成為頂尖金融機構的核心競爭力之一。它以數學模型為基礎&#xff0c;借助編程技術實現策略自動化&#xff0c;在高頻、中低頻、套利、因子投資等多個領域展現出強大生命力。對于有志于此的大學生而言&#xff0c;選擇一個…

實測AI Ping,一個大模型服務選型的實用工具

作為一名長期奮戰在一線的AI應用工程師&#xff0c;我在技術選型中最頭疼的問題就是&#xff1a;“這個模型服務的真實性能到底如何&#xff1f;” 官方的基準測試總是在理想環境下進行&#xff0c;而一旦投入使用&#xff0c;延遲波動、吞吐下降、高峰期服務不可用等問題就接踵…

深信服軟件:aTrustAgent異常占用問題處理

問題&#xff1a;aTrustAgent占用CPU 大早上開電腦&#xff0c;風扇轉的飛起&#xff0c;任務管理器看&#xff0c;發現是有幾個 aTrustAgent 進程搞得鬼。 印象中&#xff0c;好像沒有裝過這個軟件&#xff0c;搜了下&#xff0c;是深信服的軟件&#xff0c;不知道是不是裝哪…

基于國產銀河麒麟服務器SP3項目實戰(Nginx+Keepalive)實現高可用負載均衡

一、環境準備 192.168.113.11NginxKeepalive(Master)192.168.113.22Nginxkeepalive(Backup)192.168.113.33Nginx(web服務器)192.168.113.44 Nginx(服務器&#xff09; 二、環境搭建準備 2.1 Nginx源碼編譯安裝 參考作責之前發布《Nginx源碼編譯安裝》https://blog.csdn.net…

K近鄰:從理論到實踐

K近鄰&#xff1a;從理論到實踐 文章目錄K近鄰&#xff1a;從理論到實踐1. 核心思想2. 距離度量3. k的選擇與誤差分析3.1 近似誤差3.2 估計誤差3.3 總誤差4. kd樹的構造與搜索4.1 kd樹的構造4.2 kd樹的搜索5. 總結6. K近鄰用于iris數據集分類6.1加載數據6.2加載模型并可視化1. …

Dokcer的安裝(ubuntu-20.04.6):

Dokcer的安裝(ubuntu-20.04.6)&#xff1a; 1.添加Docker倉庫 #更新本地軟件包索引&#xff0c;獲取最新的軟件包信息 sudo apt-get update #安裝依賴包 sudo apt-get install -y \ ca-certificates \ curl \ gnupg \ lsb-release #創建密鑰存儲目錄 sudo mkdir -p /etc/apt/…

CT圖像重建原理

一、CT到底測了什么&#xff1f;硬件動作X 射線源與探測器陣列對置&#xff0c;圍著物體旋轉。每轉到一個角度 θ&#xff08;也叫一個視角 / view&#xff09;&#xff0c;源發射扇形/平行的射線束&#xff0c;探測器陣列上有很多“通道/像素/bin”&#xff08;記作索引 n&…

【pycharm】 ubuntu24.04 搭建uv環境

通過uv配置python環境 一直是conda環境 現在有個開源項目說用uv更快更好 所以在pycharm搞起。 一開始在在一個conda項目的里面某個項目里搞 發現會被conda 環境影響。 導致deepseed 安裝不了。 python 環境不對 # NOTE: We must explicitly request them as `dependencies` abo…

從軟件工程角度談企業管理

從軟件工程角度談企業管理企業管理&#xff0c;本質上是人與人之間的博弈。 管理的最大難題&#xff0c;不是定目標、不是寫流程&#xff0c;而是&#xff1a;如何讓個體的利益最大化路徑&#xff0c;與組織的整體目標一致&#xff1f; 這就是經濟學里的“激勵相容”。 在互聯網…

vue3 實現前端生成水印效果

vue3 實現前端生成水印效果首先一點哈&#xff0c;就是單純web前端生成水印只能作為警示使用&#xff0c;如果享徹底防住幾乎是不可能的&#xff0c;有無數種方式去掉web前端生成的水印&#xff0c;所以這種方式只當是一個君子協議吧。編寫水印組件 首先直接把這部分封裝成一個…