当前位置: 首页 > news >正文

C++:std::thread、条件变量与信号量

介绍

在多线程编程的世界里,协调不同线程之间的工作是一项极具挑战性的任务。线程可能需要等待特定条件的满足,或者对共享资源的访问进行限制。C++ 标准库为我们提供了强大的工具,如 std::thread 用于创建和管理线程,条件变量用于线程间的同步,信号量则用于控制对资源的访问。本文将通过具体的 C++ 代码示例,详细介绍如何使用这些工具。

std::thread 基础

std::thread 是 C++11 引入的用于创建和管理线程的类。它允许我们轻松地在程序中创建新的执行线程。下面是一个简单的 std::thread

#include <iostream>
#include <thread>void printMessage(const std::string& message) {std::cout << "Thread says: " << message << std::endl;
}int main() {std::thread t(printMessage, "Hello, World!");t.join();return 0;
}

定义了一个函数 printMessage,然后使用 std::thread 创建了一个新线程,并将 printMessage 函数作为线程的入口点,同时传递了一个字符串参数。join() 方法用于等待线程执行完毕。

条件变量

条件变量是一种同步原语,用于线程之间的通信和协调。它允许一个线程等待某个条件的满足,而另一个线程可以在条件满足时通知等待的线程。
生产者 - 消费者模型示例
生产者 - 消费者模型是多线程编程中常见的模式,生产者线程负责生产数据,消费者线程负责消费数据。我们可以使用条件变量来实现线程间的同步。

#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>std::queue<int> dataQueue;
std::mutex mtx;
std::condition_variable cv;
bool isProducing = true;// 生产者线程函数
void producer() {for (int i = 0; i < 5; ++i) {std::this_thread::sleep_for(std::chrono::seconds(1));{std::unique_lock<std::mutex> lock(mtx);dataQueue.push(i);std::cout << "Produced: " << i << std::endl;}cv.notify_one();}{std::unique_lock<std::mutex> lock(mtx);isProducing = false;}cv.notify_one();
}//消费者线程函数
void consumer() {while (true) {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [] { return!dataQueue.empty() ||!isProducing; });if (!dataQueue.empty()) {int value = dataQueue.front();dataQueue.pop();std::cout << "Consumed: " << value << std::endl;} else if (!isProducing) {break;}}
}int main() {std::thread producerThread(producer);std::thread consumerThread(consumer);producerThread.join();consumerThread.join();return 0;
}

std::queue dataQueue:用于存储生产者生产的数据。
std::mutex mtx:用于保护对 dataQueue 的访问,确保线程安全。
std::condition_variable cv:用于线程间的同步。
producer() 函数:生产者线程每隔 1 秒生产一个数据,并将其加入队列。生产完成后,通知消费者线程。
consumer() 函数:消费者线程等待条件变量的通知,当队列中有数据时,从队列中取出数据进行消费。
cv.wait(lock, [] { return!dataQueue.empty() ||!isProducing; }):消费者线程等待,直到队列非空或者生产结束。

信号量

信号量是一种用于控制对资源访问的同步原语。在 C++ 标准库中,并没有直接提供信号量的实现,可以使用 std::mutex 和 std::condition_variable 来模拟信号量。
信号量的实现

#include <mutex>
#include <condition_variable>class Semaphore {
public:Semaphore(int count = 0) : count_(count) {}void notify() {std::unique_lock<std::mutex> lock(mtx_);++count_;cv_.notify_one();}void wait() {std::unique_lock<std::mutex> lock(mtx_);cv_.wait(lock, [this] { return count_ > 0; });--count_;}private:int count_;std::mutex mtx_;std::condition_variable cv_;
};
#include <iostream>
#include <thread>
#include <vector>Semaphore sem(2); // 允许最多 2 个线程同时访问资源void accessResource(int id) {sem.wait();std::cout << "Thread " << id << " is accessing the resource." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Thread " << id << " has finished accessing the resource." << std::endl;sem.notify();
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 5; ++i) {threads.emplace_back(accessResource, i);}for (auto& t : threads) {t.join();}return 0;
}

Semaphore 类:实现了一个简单的信号量。notify() 方法用于增加信号量的值并通知等待的线程,wait() 方法用于等待信号量的值大于 0 并减少信号量的值。
accessResource() 函数:线程在访问资源前调用 sem.wait() 等待信号量,访问完成后调用 sem.notify() 释放信号量。
emplace_back 是 C++ 标准库容器(如 std::vector、std::deque 等)提供的一个成员函数,它主要用于在容器的尾部直接构造一个新元素。

结论

通过 std::thread、条件变量和信号量,可以在 C++ 中实现复杂的多线程程序。条件变量用于线程间的同步,确保线程在特定条件满足时才继续执行;信号量用于控制对资源的访问,避免资源竞争。合理使用这些工具可以提高程序的性能和稳定性。希望本文能帮助你更好地理解和应用这些多线程编程的重要概念。

相关文章:

C++:std::thread、条件变量与信号量

介绍 在多线程编程的世界里&#xff0c;协调不同线程之间的工作是一项极具挑战性的任务。线程可能需要等待特定条件的满足&#xff0c;或者对共享资源的访问进行限制。C 标准库为我们提供了强大的工具&#xff0c;如 std::thread 用于创建和管理线程&#xff0c;条件变量用于线…...

POI pptx转图片

前言 ppt页面预览一直是个问题&#xff0c;office本身虽然有预览功能但是收费&#xff0c;一些开源的项目的预览又不太好用&#xff0c;例如开源的&#xff1a;kkfileview pptx转图片 1. 引入pom依赖 我这个项目比较老&#xff0c;使用版本较旧 <dependency><gro…...

Java File 类

File 类是 Java 中用于处理文件和目录的基本类之一&#xff0c;位于 java.io 包中。它提供了多种方法来创建、删除、检查、修改文件或目录的属性&#xff0c;以及列出文件夹中的内容。虽然 File 类本身不提供直接的读取或写入文件内容的方法&#xff08;这些操作通常由 FileInp…...

工业通信协议 EtherNet/IP 全面解析

工业通信协议 EtherNet/IP 全面解析 EtherNet/IP&#xff08;以太网工业协议&#xff09;是一种基于标准以太网的工业自动化通信协议&#xff0c;由 ODVA&#xff08;开放设备网供应商协会&#xff09; 管理。它融合了 CIP&#xff08;通用工业协议&#xff09; 和以太网技术&…...

使用docker配置PostgreSQL

配置docker阿里云镜像仓库 国内使用docker hub拉取镜像比较慢&#xff0c;所以首先配置个人的镜像仓库。 阿里云的个人镜像仓库是免费的&#xff0c;对个人来说足够用。 具体操作参考阿里云官方链接 。 关于个人镜像仓库的使用参考链接。 配置完个人镜像仓库后将公网配置到doc…...

UITextView删除原有字符串时,光标会上移并且光标会变高

代码运行效果如图&#xff1a; import Foundationclass TestVC: UIViewController {override func viewDidLoad() {super.viewDidLoad()let testV MyCustomTextView(frame: CGRect(x: 0, y: 130, width: SCREEN_WIDTH - 50, height: 170))self.view.addSubview(testV)testV.ba…...

python入门 介绍及变量的使用

1.python介绍 python 是一门计算机语言 常见的计算机语言&#xff1a;python、java、C语言。。。 什么是计算机语言&#xff1a;就是让计算机知道你想干什么&#xff0c;把你的需求使用它能听懂的语言说出来 中国也有一门计算机语言&#xff1a;易语言 能认为是语言的本质上…...

51单片机-按键

1、独立按键 1.1、按键介绍 轻触开关是一种电子开关&#xff0c;使用时&#xff0c;轻轻按开关按钮就可使开关接通&#xff0c;当松开手时&#xff0c;开关断开。 1.2、独立按键原理 按键在闭合和断开时&#xff0c;触点会存在抖动现象。P2\P3\P1都是准双向IO口&#xff0c;…...

Java 8 至 Java 23 版本特性对比表

Java现在发布的版本很快&#xff0c;每年两个&#xff0c;但是真正会被大规模使用的是三年一个的TLS版本。 版本年份LTS关键特性影响力等级Java 82014✅Lambda 表达式、Stream API、方法引用、接口默认方法、Optional 类⭐⭐⭐⭐⭐Java 92017❌模块化系统&#xff08;JPMS&…...

在wsl环境中配置和开发verilog(一种比较新颖的verilog开发指南)

WSL是windows中自带的linux子系统&#xff0c;笔者在若干月前首次接触其便爱不释手&#xff0c;verilog作为一种硬件解释语言&#xff0c;可否像c语言那样被游刃有余的编译和运行呢&#xff0c;笔者这次大胆的尝试在WSL环境VSCODEIverilog开发verilog。 首先默认按照了WSL和VS…...

AI学习指南HuggingFace篇-Hugging Face 的核心工具

一、引言 Hugging Face作为AI领域的重要参与者,提供了许多强大的工具,极大地简化了自然语言处理(NLP)任务的开发流程。其中,Transformers、Datasets 和 Tokenizers 是Hugging Face的三大核心工具。本文将深入介绍这些工具的作用、功能以及它们如何相互配合,帮助读者更好…...

DeepSeek 助力 Vue 开发:打造丝滑的二维码生成(QR Code)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…...

QT 引入Quazip和Zlib源码工程到项目中,无需编译成库,跨平台,压缩进度

前言 最近在做项目时遇到一个需求&#xff0c;需要将升级的文件压缩成zip&#xff0c;再进行传输&#xff1b; 通过网络调研&#xff0c;有许多方式可以实现&#xff0c;例如QT私有模块的ZipReader、QZipWriter&#xff1b;或者第三方库zlib或者libzip或者quazip等&#xff1…...

深入解析桥接模式:软件设计中的解耦利器

桥接模式&#xff1a;软件设计中的解耦利器 在软件开发的复杂世界中&#xff0c;设计模式是开发者解决常见问题的有力工具。桥接模式作为一种重要的结构型设计模式&#xff0c;在处理抽象与实现的关系时展现出独特的优势&#xff0c;它能够巧妙地将抽象部分与实现部分分离&…...

MYSQL-数据库-DDL-DML-DQL-DCL-基础学习

MySql概念&#xff1a; 建立在关系模型基础上&#xff0c;有多张相互连接的二维表组成的数据库 SQL通用语法&#xff1a; 1.SQL语句可以单行或多行书写&#xff0c;以分号结尾 2.SQL语句可以使用空格/缩进来增强语句的可读性 3.MySQL数据库的SQL语句不区分大小写&#xff0c;关…...

rv1126解码的一些原理

rv1126解码篇中&#xff0c;出现最重要的两个api一个是&#xff0c;send_vdec_thread线程里面调用的RK_MPI_SYS_SendMediaBuffer&#xff0c;把数据发到解码器。另外一个是read_vdec_thread线程的RK_MPI_SYS_GetMediaBuffer获取解码器里面的数据。 今天想探讨一下他的底层原理。…...

二级公共基础之数据结构与算法篇(七)排序技术

目录 前言 一、交换类排序 1.冒泡排序法 1. 冒泡排序的思想 2. 冒泡排序的实现步骤 3. 示例 4. 冒泡排序的特点 2.快速排序 1. 快速排序的核心思想 2. 快速排序的实现步骤 3. 示例代码(C语言) 4. 快速排序的特点 二、插入类排序 1. 简单插入排序 1.简单插入排…...

深蕾科技智能多媒体SoC产品助力“DataEye剧查查之夜”微短剧盛会

深蕾科技助力微短剧盛会 深圳湾“DataEye剧查查之夜”微短剧盛会&#xff0c;于2025年2月20日18:00点&#xff0c;在深圳湾盛大开启。作为第十四届中国国际新媒体短片节的重要组成部分&#xff0c;“剧查查之夜”汇聚了微短剧行业的顶尖力量&#xff0c;吸引了众多大咖齐聚一堂…...

Apache Doris 实现毫秒级查询响应

1. 引言 1.1 数据分析的重要性 随着大数据时代的到来,企业对实时数据分析的需求日益增长。快速、准确地获取数据洞察成为企业在竞争中脱颖而出的关键。传统的数据库系统在处理大规模数据时往往面临性能瓶颈,难以满足实时分析的需求。例如,一个电商公司需要实时监控销售数据…...

计算机考研之数据结构:P 问题和 NP 问题

在算法的时间复杂度估算中&#xff0c;通常教材和题目中的估算结果包括&#xff1a; O ( 1 ) , O ( log ⁡ n ) , O ( n ) , O ( n ) , O ( n log ⁡ n ) , O ( n 2 ) , O ( n 3 ) , O ( log ⁡ log ⁡ n ) O(1),O(\log{n}),O(\sqrt{n}),O(n),O(n\log{n}),O(n^2),O(n^3),O(\log…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践

在 Kubernetes 集群中&#xff0c;如何在保障应用高可用的同时有效地管理资源&#xff0c;一直是运维人员和开发者关注的重点。随着微服务架构的普及&#xff0c;集群内各个服务的负载波动日趋明显&#xff0c;传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...