C++20 semaphore(信号量) 详解
头文件在C++20中是并发库技术规范(Technical Specification, TS)的一部分。信号量是同步原语,帮助控制多线程程序中对共享资源的访问。头文件提供了标准C++方式来使用信号量。
使用环境
Windows:VS中打开项目属性,修改C++语言标准。
Linux:GCC,版本至少应为10.1,编译命令中使用-std=c++20标志。
简单定义
你可以像这样创建一个信号量对象:
std::counting_semaphore<size_t> sem(1); // 用初始计数为1初始化一个信号量
std::counting_semaphore是一种允许指定数量的线程同时访问资源的信号量。在这个例子中,一次只有一个线程可以访问由sem保护的资源。
获取和释放
直接获取
要获取(锁定)信号量,你可以使用acquire方法:
sem.acquire();
// 关键段代码
sem.release();
acquire方法将信号量计数减一,有效地锁定它。release方法增加计数,释放信号量。
尝试获取
你也可以使用try_acquire方法来尝试获取信号量而不阻塞:
if (sem.try_acquire()) {// 成功获取了信号量// 关键段代码sem.release();
} else {// 信号量未被获取
}
带超时的等待
C++20还引入了try_acquire_for和try_acquire_until方法,以带超时的方式尝试获取信号量。
if (sem.try_acquire_for(std::chrono::seconds(1))) {// 在1秒内成功获取了信号量// 关键段代码sem.release();
} else {// 在1秒内未能获取信号量
}
信号量的类型
std::counting_semaphore
计数信号量是一种同步原语,允许多个线程在一定限制下访问共享资源。它是互斥锁或二进制信号量的泛化。
你可以用一个初始计数来初始化计数信号量,该计数代表可以同时无阻塞访问资源的线程数量。线程可以获取和释放计数,信号量的计数相应地增加或减少。如果线程尝试获取的计数超过了可用的数量,它将阻塞,直到计数变得可用。
// 展示如何使用counting_semaphore
#include <iostream>
#include <semaphore>
#include <thread>
using namespace std;// 用3个计数初始化信号量
counting_semaphore<10> semaphore(3);void worker(int id)
{// 获取semaphore.acquire();// 执行一些工作cout << "Thread " << id << " acquired the semaphore."<< endl;// 释放semaphore.release();cout << "Thread " << id << " released the semaphore."<< endl;
}int main()
{thread t1(worker, 1);thread t2(worker, 2);thread t3(worker, 3);t1.join();t2.join();t3.join();return 0;
}
输出结果
Thread 2 acquired the semaphore.
Thread 2 released the semaphore.
Thread 1 acquired the semaphore.
Thread 1 released the semaphore.
Thread 3 acquired the semaphore.
Thread 3 released the semaphore.
std::binary_semaphore
二进制信号量是一种更简单的信号量版本,它只能有两个值:0和1。
通常用于两个线程之间的基本互斥或信号传递。可以被视为具有更轻量级接口的互斥锁。类似于mutex。
// 展示二进制信号量的用法
#include <iostream>
#include <semaphore>
#include <thread>
using namespace std;// 用1个计数(二进制)初始化信号量
binary_semaphore semaphore(1);void worker(int id)
{// 获取信号量semaphore.acquire();cout << "Thread " << id << " acquired the semaphore."<< endl;// 执行一些工作semaphore.release();// 释放信号量cout << "Thread " << id << " released the semaphore."<< endl;
}int main()
{thread t1(worker, 1);thread t2(worker, 2);t1.join();t2.join();return 0;
}
输出结果
Thread 1 acquired the semaphore.
Thread 1 released the semaphore.
Thread 2 acquired the semaphore.
Thread 2 released the semaphore.
优点
信号量的优势如下:
- 精细控制:信号量可以配置为允许特定数量的线程同时访问资源,实现资源的精细控制。
- 通用性:信号量更加灵活多样,可以用来实现其他同步原语。
- 多资源管理:计数信号量可以用来管理多个资源实例,适用于需要控制对资源池(如线程池或连接池)访问的场景。
- 阻塞等待:信号量中的阻塞和等待机制允许线程等待直到资源再次可用。
- 超时处理:在获取信号量时可以指定超时,使其更加实用。
例子:生产者消费者问题
#include <iostream>
#include <semaphore>
#include <thread>
using namespace std;const int buffer_size = 5;// 缓冲区大小
std::binary_semaphore b_mutex(1);
//容量为5 赋初值
std::counting_semaphore<buffer_size> b_full(0);
std::counting_semaphore<buffer_size> b_empty(5);
void Producer()
{while (true){b_empty.acquire();b_mutex.acquire();std::cout << "Producer\n";b_mutex.release();b_full.release();//模拟生成过程std::this_thread::sleep_for(std::chrono::seconds(2));}
}
void Consumer()
{while (true){b_full.acquire();b_mutex.acquire();std::cout << "Consumer\n";b_mutex.release();b_empty.release();//模拟消耗过程std::this_thread::sleep_for(std::chrono::seconds(2));}
}
int main()
{thread t0(Producer);thread t1(Producer);thread t2(Consumer);thread t3(Consumer);t0.join();t1.join();t2.join();t3.join();
}
关键组件
b_mutex:一个二进制信号量,用作互斥锁,保证在任何时刻只有一个线程可以操作缓冲区。这是为了防止多个生产者或消费者同时访问缓冲区,导致数据不一致的问题。
b_full:一个计数信号量,表示缓冲区中已填充的项数。初始化为0,因为一开始缓冲区是空的。
b_empty:另一个计数信号量,表示缓冲区中空闲位置的数量。初始化为缓冲区的大小,因为起初整个缓冲区都是空的。
生产者(Producer)
等待一个空闲位置(b_empty.acquire();),这表示生产者在缓冲区中找到了一个可以放置新生产项的位置。
获取互斥锁(b_mutex.acquire();),进行生产操作(这里通过打印"Producer"模拟),然后释放互斥锁(b_mutex.release();),这样其他线程(生产者或消费者)就可以访问缓冲区了。
生产完成后,释放一个已满位置的信号(b_full.release();),告知消费者缓冲区中有项可被消费。模拟生产过程中的延迟(std::this_thread::sleep_for(std::chrono::seconds(2));)。
消费者(Consumer)
等待一个已满位置(b_full.acquire();),这表示消费者在缓冲区中找到了一个可以消费的项。
获取互斥锁(b_mutex.acquire();),进行消费操作(这里通过打印"Consumer"模拟),然后释放互斥锁(b_mutex.release();),这样其他线程(生产者或消费者)就可以访问缓冲区了。
消费完成后,释放一个空闲位置的信号(b_empty.release();),告知生产者缓冲区中有位置可用于生产新的项。模拟消费过程中的延迟(std::this_thread::sleep_for(std::chrono::seconds(2));)。
相关文章:
C++20 semaphore(信号量) 详解
头文件在C20中是并发库技术规范(Technical Specification, TS)的一部分。信号量是同步原语,帮助控制多线程程序中对共享资源的访问。头文件提供了标准C方式来使用信号量。 使用环境 Windows:VS中打开项目属性,修改C语…...
【简单讲解下Lisp的学习历程】
🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…...
构建高效网络:深入理解正向与反向代理的作用与配置
正向代理 如果把局域网外的互联网环境想象成一个巨大的资源库,则局域网中的客户端要访问互联网则需要通过代理服务器来访问,这种代理成为正向代理。 示例: 用户想要访问 https://chensir.ink (目标服务器)࿰…...
Linux:make/makefile的使用
一、什么是makefile/make 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的 规则来指定,哪些文件需要先编译&am…...
Java设计模式—策略模式(商场打折)
策略这个词应该怎么理解,打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。 再比如我们去逛商场,商场现在正在搞活动&…...
FOR循环
oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 前面两种循环都要根据条件是否成立而确定循环体的执行,具体循环体执行多少次事先并不知道。 FOR 循环可以控制循环执行的次数,由循环变量控制循环体的…...
C++: 命名空间/C++输入输出/缺省参数/函数重载/引用/内联函数
进入C以后,就翻开了新的篇章。C支持C语言的使用。事实上,C是创建者在发现C语言中有很多不好用的地方(在后续学习中会明显看到)后,在C语言基础上又加入了许多语法,于是就成了C。 1.命名空间 来源ÿ…...
Java | Leetcode Java题解之第13题罗马数字转整数
题目: 题解: class Solution {Map<Character, Integer> symbolValues new HashMap<Character, Integer>() {{put(I, 1);put(V, 5);put(X, 10);put(L, 50);put(C, 100);put(D, 500);put(M, 1000);}};public int romanToInt(String s) {int …...
题目:学习使用register定义变量的方法。
题目:学习使用register定义变量的方法。 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated …...
IO_DAY7
1:实现2个终端之间的互相聊天 要求:千万不要做出来2个终端之间的消息发送是读一写的,一定要能够做到,一个终端发送n条消息,另一个终端一条消息都不回复都是没有问题的 终端A: #include<myhead.h> int main(int argc, char…...
大模型学习笔记八:手撕AutoGPT
文章目录 一、功能需求二、演示用例三、核心模块流程图四、代码分析1)Agent类目录创建智能体对象2)开始主流程3)在prompt的main目录输入主prompt和最后prompt4)增加实际的工具集tools(也就是函数)5…...
Java常用API_System——常用方法及代码演示
1.System.exit(int status) 方法的形参int status为状态码,如果是0,说明虚拟机正常停止,如果非0,说明虚拟机非正常停止。需要将程序结束时可以调用这个方法 代码演示: public class Test {public static void main(S…...
neo4j图数据库下载安装配置
neo4j下载地址Index of /doc/neo4j/3.5.8/ 1.说明:jdk 1.8 版本对应的 neo4j 数据库版本 推荐安装3.X版本 2.配置系统环境变量 3.启动 neo4j.bat console 4.访问...
结构化面试-有矛盾的人际沟通题
例题一: 你和小张一起值班,但是小张没来,刚好领导检查发现后批评了他,事后小张埋怨你, 认为你在领导面前表现,并在同事中传播,同事也觉得你不通人情,你怎么处理? 回答&a…...
AI技术创业机会之金融科技
金融科技服务(FinTech)领域正经历着一场由人工智能(AI)技术引领的深刻变革,为创业者提供了无数创新与颠覆传统金融服务模式的机会。以下详述了金融科技服务中AI技术的具体创业机会及其细节与内容,以期为有志于涉足此领域的创业者提供全面的洞察与参考。 一、智能投顾与财…...
LC低通滤波
LC滤波器,是指将电感L与电容器 C进行组合设计构成的滤波电路,可去除或通过特定频率的无源器件。电容器具有隔直流通交流,且交流频率越高越容易通过的特性。而电感则具有隔交流通直流,且交流频率越高越不易通过的特性。因此&#x…...
CS162 Operating System笔记
What is an Operating System? it’s typically a special layer of software that provides the application access to hardware resources.So.it’s convenient abs fractions of complex hardware devices....
mysql慢sql排查与分析
当MySQL遇到慢查询(慢SQL)时,我们可以通过以下步骤进行排查和优化: 标题开启慢查询日志: 确保MySQL的慢查询日志已经开启。通过查看slow_query_log和slow_query_log_file变量来确认。 如果没有开启,可以…...
基于Springboot+Vue实现前后端分离酒店管理系统
一、🚀选题背景介绍 📚推荐理由: 近几年来,随着各行各业计算机智能化管理的转型,以及人们经济实力的提升,人们对于酒店住宿的需求不断的提升,用户的增多导致酒店管理信息的不断增多,…...
2024泰迪杯c题详细思路代码讲解:竞赛论文的辅助自动评阅
C:竞赛论文的辅助自动评阅 步骤一:理解拆解题目,并对附件1中的论文集进行初步分析。 步骤二:特征构造 论文完整性:开发算法以检查论文是否全面回答了赛题。这包括自然语言处理(NLP)技术来识别关键段落和论证的完整…...
新手友好:无需配置环境,在快马平台编写第一行open claw控制代码
今天想和大家分享一个特别适合新手入门的Open Claw控制小项目。作为一个刚接触机器人控制的小白,我发现在InsCode(快马)平台上可以轻松实现机械爪的基础控制,完全不需要配置复杂的环境,特别适合零基础学习。 Open Claw是什么? Ope…...
新手福音:用快马AI生成带详细注释的Hello World安装包项目
作为一名刚接触Python编程的新手,我最近尝试为自己的第一个图形界面程序制作安装包。这个过程让我深刻体会到,传统打包工具的学习曲线对初学者来说确实不太友好。不过通过InsCode(快马)平台的AI辅助功能,整个流程变得异常简单。下面分享我的实…...
安卓开发工程师(无人售卖机方向):核心技术解析与实践指南
引言:智能零售浪潮下的安卓开发新机遇 随着物联网(IoT)技术、移动支付、人工智能等技术的飞速发展与深度融合,无人零售业态正经历一场深刻的变革。无人售卖机(或称自动售货机)作为其中的典型代表,已从简单的投币式机械装置,演变为集成了多种传感器、支付模块、通信模块、…...
本体论与知识图谱有什么区别?
目录 一、基础定义拆解 1. 本体论(Ontology) 2. 知识图谱(Knowledge Graph) 二、核心区别多维对比 三、内在联系 四、举例 往期精彩 一、基础定义拆解 1. 本体论(Ontology) 起源:哲学概…...
OpenClaw镜像体验:在星图GPU平台快速试用SecGPT-14B安全分析
OpenClaw镜像体验:在星图GPU平台快速试用SecGPT-14B安全分析 1. 为什么选择云平台体验OpenClaw 第一次接触OpenClaw时,我被它的自动化能力吸引,但本地安装过程让我望而却步。作为一个经常需要评估各种AI工具的安全工程师,我发现…...
基于工件高度检测的机电传动与控制:factory建模博图v16plc程序的设计任务
机电传动与控制,基于工件高度检测的分拣(A)控制系统设计任务 内容:factory 建模博图 v16plc 程序(v16 版本以上均可使用)传送带上的金属工件哐当哐当地滑过,突然被机械臂稳稳抓取——这看似简单的动作背后藏着精密的高…...
HAL_NVIC
文章目录一、NVIC简介 NVIC 做什么?二、NVIC模块详解 1、NVIC 寄存器 2、优先级的定义 1.优先级寄存器NVIC_IPRx 2.优先级分组3、NVIC 工作完整流程 4、F103中断向量表 1.内核异常向量(固定,所有 CM…...
你的Windows Defender是否正在拖慢系统性能?3步彻底解决方案
你的Windows Defender是否正在拖慢系统性能?3步彻底解决方案 【免费下载链接】windows-defender-remover A tool which is uses to remove Windows Defender in Windows 8.x, Windows 10 (every version) and Windows 11. 项目地址: https://gitcode.com/gh_mirro…...
AI万能分类器应用解析:零样本分类在舆情分析中的实际价值
AI万能分类器应用解析:零样本分类在舆情分析中的实际价值 1. 引言 每天,互联网上产生数以亿计的文本数据——社交媒体评论、新闻报道、用户反馈、论坛讨论...这些数据蕴含着宝贵的舆情信息,但如何从中快速识别关键话题和情感倾向࿰…...
清华大学重磅突破:让AI汽车真正听懂你说话,想去哪就去哪!
这项由清华大学计算机科学与技术系和GigaAI公司联合开展的研究于2026年3月26日发表在计算机视觉顶级会议论文中,论文编号为arXiv:2603.25741v1。有兴趣深入了解技术细节的读者可以通过该编号查询完整论文内容。汽车能像人类司机一样理解复杂的语言指令,并…...
