目录

前言

学习目标

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;所以这种方式只当是一个君子协议吧。编写水印组件 首先直接把这部分封装成一个…