[Linux]条件变量:实现线程同步(什么是条件变量、为什么需要条件变量,怎么使用条件变量(接口)、例子,代码演示(生产者消费者模式))
目录
一、条件变量
1.什么是条件变量
故事说明
2、为什么需要使用条件变量
竞态条件
3.什么是同步
饥饿问题
二、条件变量的接口
1.pthread_cond_t
2.初始化(pthread_cond_init)
3.销毁(pthread_cond_destroy)
4.等待(pthread_cond_wait)
5.唤醒(pthread_cond_signal && pthread_cond_broadcast)
pthread_cond_signal
pthread_cond_broadcast
三、使用演示 (模拟生产者消费者模式)
一、条件变量
1.什么是条件变量
条件变量(Condition Variable)是一种用于线程同步的机制,通常与互斥锁(Mutex)一起使用。条件变量提供了一种线程间的通信机制,允许一个线程等待另一个线程满足某个条件后再继续执行。
故事说明
现在小明要在在一张桌子上放一个苹果,而旁边有一群蒙着眼睛的人,因为他们的眼睛被蒙着,他们如果想拿到这个苹果,就会时不时来桌子前摸一摸看看桌子是否有苹果,并且谁来桌子前摸苹果是无序的,这时的场面就很混乱,小明一看不行,于是小明就桌子上放了个铃铛,并且组织需要苹果的人排好队,有苹果小米就会摇响铃铛,排在第一个的人就拿走苹果,排到队尾等待被唤醒。此时混乱的场面就显得尽然有序了。在本故事中,小明就是操作系统,苹果就是临界资源,一群蒙着眼睛都人就是多线程,铃铛就是条件变量,排队就是实现同步,摇响铃铛就是唤醒线程。
2、为什么需要使用条件变量
使用条件变量主要是因为它们提供了在多线程编程中一种有效的同步机制。当多个线程需要等待某个特定条件成立才能继续执行时,条件变量就显得尤为重要。通过条件变量,线程可以安全地进入等待状态,直到被其他线程显式地唤醒或满足等待的条件。这有助于避免线程的无谓轮询或忙等待,提高了系统的响应能力和效率。
注意:在使用条件变量时,必须确保与互斥锁一起使用,以避免竞态条件的发生。
竞态条件
竞态条件(Race Condition)是指在设备或系统尝试同时执行两个或多个操作时,由于操作顺序不当而导致的不期望的结果。简单来说就是因为时序问题,而导致程序异常。
3.什么是同步
在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步。
饥饿问题
饥饿问题指的是某些线程由于某种原因无法获得它们所需要的资源或执行机会,导致它们长时间得不到处理,甚至永远得不到处理的现象。这种情况通常发生在多个线程竞争有限资源时,其中一些线程可能因为优先级过低、调度算法的不公平性、同步机制使用不当或其他原因而无法获得足够的执行时间。
二、条件变量的接口
1.pthread_cond_t
pthread_cond_t是 POSIX 线程库(Pthreads)中用于表示条件变量的数据类型。
2.初始化(pthread_cond_init)
功能:初始化条件变量
原型#include <pthread.h>
方式一(pthread_cond_t是局部全局都可以用):
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
方式二(pthread_cond_t是全局变量时):
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;注意:
restrict是一个类型限定符,它用于告知编译器两个指针不会指向同一个内存位置,这样编译器可以生成更高效的代码参数
cond:一个指向pthread_cond_t类型的指针,用于存储初始化后的条件变量。attr:一个指向pthread_condattr_t类型的指针,用于指定条件变量的属性。通常可以传递NULL(nullptr),以使用默认属性。返回值
- 如果成功,返回 0。
- 如果失败,返回错误码。
使用例子:
#include <pthread.h> #include <stdio.h> pthread_cond_t cond; // 全局 pthread_cond_t 变量 int main() { int rc; // 显式初始化全局 pthread_cond_t 变量 rc = pthread_cond_init(&cond, NULL); if (rc != 0) { printf("Cond init failed: %d\n", rc); return 1; } // ... 其他代码,包括线程创建和同步 ... // 在不再需要条件变量时销毁它 //...return 0; }
3.销毁(pthread_cond_destroy)
功能:销毁条件变量
原型#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
参数
cond:指向要销毁的条件变量的指针。返回值
- 如果成功,返回 0。
- 如果失败,返回错误码。
4.等待(pthread_cond_wait)
功能:阻塞当前线程,直到指定的条件变量被其他线程信号通知或广播。
原型#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);参数
cond:指向条件变量的指针。mutex:指向互斥锁的指针,该互斥锁应该在调用pthread_cond_wait之前由当前线程锁定。返回值
- 如果成功,返回 0。
- 如果失败,返回错误码。
5.唤醒(pthread_cond_signal && pthread_cond_broadcast)
pthread_cond_signal
功能:唤醒正在等待特定条件变量的一个线程
原型#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
参数
cond:指向要发送信号(广播)的条件变量的指针。返回值
- 如果成功,返回 0。
- 如果失败,返回错误码。
pthread_cond_broadcast
功能:用于唤醒所有正在等待指定条件变量的线程
原型#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
参数
cond:指向要发送信号(广播)的条件变量的指针。返回值
- 如果成功,返回 0。
- 如果失败,返回错误码。
三、使用演示 (模拟生产者消费者模式)
说明:模拟生产者消费者模式
注意:使用pthrad原生线程库(POSIX库)要链接库:-lpthread
不会连接动态库的可以看我这篇文章:[Linux]动静态库(什么是动静态库,怎么生成动静态库,怎么使用(连接)动静态库)-CSDN博客
cond.cc
#include <iostream>
#include <pthread.h>
#include <vector>
#include <string>
#include <unistd.h>
using namespace std;// 定义条件变量和互斥锁
// 全局的初始化方式
pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 共享变量,用于线程间的同步
int shared_data = 0;// 线程函数,模拟生产者
void *producer(void *args)
{string producer_name = static_cast<char *>(args);// 生产数据,并通知消费者while (1){// 锁定互斥锁pthread_mutex_lock(&mutex);// 生产数据(这里只是简单地递增shared_data)shared_data++;cout << "I is " << producer_name << " "<< " Producer produced data: "<< shared_data << endl;// 唤醒等待的消费者线程pthread_cond_signal(&cond_var);// 解锁互斥锁pthread_mutex_unlock(&mutex);// 模拟生产耗时sleep(1);}return nullptr;
}// 线程函数,模拟消费者
void *consumer(void *args)
{string consumer_name = static_cast<char *>(args);// 消费数据while (1){// 锁定互斥锁pthread_mutex_lock(&mutex);// 等待生产者生产数据while (shared_data == 0){// 等待条件变量,解锁互斥锁,进入等待状态pthread_cond_wait(&cond_var, &mutex);}// 消费数据(这里只是简单地递减shared_data)shared_data--;cout << "I is " << consumer_name << " "<< " Consumer consumed data: "<< shared_data << endl;cout << "-----------------------------------"<< endl;// 解锁互斥锁pthread_mutex_unlock(&mutex);// 模拟消费耗时sleep(4);}return nullptr;
}int main()
{int producer_thread_num = 5; // 生产者人数int consumer_thread_num = 10; // 消费者人数vector<pthread_t> producers;vector<pthread_t> consumers;for (int i = 0; i < producer_thread_num; i++){pthread_t producer_thread; // 生产者char buffer[64];sprintf(buffer, "producer-%d", i + 1);// 创建生产者线程if (pthread_create(&producer_thread, nullptr, producer, buffer) != 0){perror("pthread_create producer");exit(EXIT_FAILURE);}producers.push_back(producer_thread);//保存pthread_t,以备等待回收}for (int i = 0; i < consumer_thread_num; i++){pthread_t consumer_thread; // 消费者// 创建消费者线程char buffer[64];sprintf(buffer, "consumer-%d", i + 1);if (pthread_create(&consumer_thread, nullptr, consumer, buffer) != 0){perror("pthread_create consumer");exit(EXIT_FAILURE);}consumers.push_back(consumer_thread);//保存pthread_t,以备等待回收}// 等待线程结束for (auto& thraed:producers){ pthread_join(thraed, nullptr);}for (auto& thraed:consumers){ pthread_join(thraed, nullptr);}// 销毁条件变量pthread_cond_destroy(&cond_var);// 销毁锁pthread_mutex_destroy(&mutex);return 0;
}
Makefile
mycond:cond.ccg++ -o $@ $^ -std=c++11 -lpthread
PHONY:clean
clean:rm -f mycond
结果

相关文章:
[Linux]条件变量:实现线程同步(什么是条件变量、为什么需要条件变量,怎么使用条件变量(接口)、例子,代码演示(生产者消费者模式))
目录 一、条件变量 1.什么是条件变量 故事说明 2、为什么需要使用条件变量 竞态条件 3.什么是同步 饥饿问题 二、条件变量的接口 1.pthread_cond_t 2.初始化(pthread_cond_init) 3.销毁(pthread_cond_destroy) 4.等待&…...
从Java到json:探索 Jackson 的魔力
引言 Jackson简介 Jackson是一个用于处理JSON数据的开源Java库。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和编写,同时也易于计算机解析和生成。在Java领域,Jackson已经成为处理JSON数据的事实标准库。它提供了丰富的功能,包括将Java对象转…...
Docker之docker compose!!!!
一、概述 是 Docker 官方提供的一款开源工具,主要用于简化在单个主机上定义和运行多容器 Docker 应用的过程。它的核心作用是容器编排,使得开发者能够在一个统一的环境中以声明式的方式管理多容器应用的服务及其依赖关系。 也就是说Docker Compose是一个…...
shardingsphere+达梦+jpa项目改造适配中遇到的一些问题与解决
问题一:shardingsphere.dialect.exception.syntax.database.UnknownDatabaseException 解决: jdbcTemplate 类注入有问题,如: 1)如果使用Resource注解引入该类时,变量名需要与初始化时Bean修饰的方法名相…...
YOLOV9训练自己的数据集
1.代码下载地址GitHub - WongKinYiu/yolov9: Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information 2.准备自己的数据集 这里数据集我以SAR数据集为例 具体的下载链接如下所示: 链接:https:/…...
UG NX二次开发(C++)-CAM-获取加工操作的四种方法
文章目录 1、前言2、采用选中工序导航器获取操作的Tag_t3、采用遍历对象的方法获取操作的Tag_t4、采用Collection遍历获取操作对象NXOpen::CAM::Operation5、采用FindObject获取操作对象NXOpen::CAM::Operation6、以上4种方法封装成类 Class CAMOperation6.1 CAMOperation.h文件…...
python共享单车信息系统的设计与实现flask-django-php-nodejs
课题主要分为二大模块:即管理员模块和用户模块,主要功能包括:用户、区域、共享单车、单车租赁、租赁归还、报修信息、检修信息等; 语言:Python 框架:django/flask 软件版本:python3.7.7 数据库…...
Python之Web开发中级教程----Django站点管理
Python之Web开发中级教程----Django站点管理 网站的开发分为两部分:内容发布和公共访问 内容发布是由网站的管理员负责查看、添加、修改、删除数据 Django能够根据定义的模型类自动地生成管理模块 使用Django的管理模块, 需要按照如下步骤操作 : 1.管理界面本地…...
Spring Boot项目中使用MyBatis连接达梦数据库6
在开发中,使用Spring Boot框架结合MyBatis来操作数据库是一种常见的做法。本篇博客将介绍如何在Spring Boot项目中配置MyBatis来连接达梦数据库6,并提供一个简单的示例供参考。(达梦六不仅分表还分模式.) 我拿SYSTEM表的LPS模式下面Student表做案例。 1.…...
Matlab快捷键与函数
注释:注释对于代码的重要性我们就不做过多的解释了。不做注释的代码不是好代码。选中要注释的语句,按快捷键CtrlR,或者在命令行窗口上面的注释地方可以进行注释。当然也可以直接在语句前面“%”就可以(注意:一定要用英文符号&…...
接雨水-热题 100?-Lua 中文代码解题第4题
接雨水-热题 100?-Lua 中文代码解题第4题 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 1: 输入:height [0,1,0,2,1,0,1,3,2,1,2,1] 输出:6 解释…...
JVM内存溢出排查
JVM内存溢出排查主要涉及到定位问题发生的原因以及确定哪些对象占用了过多的内存。以下是一些排查内存溢出的基本步骤: 查看异常信息: 当JVM发生内存溢出时,会抛出OutOfMemoryError异常,并伴随异常信息。这些信息可以帮助初步定位…...
Leetcode 200. 岛屿数量
心路历程: 在没有看图论这一章之前看这道题没什么直接的思路,在看完图论之后,学着使用DFS和BFS去套用解决。第一次自己做的时候还是遇到了很多小问题。整体思路很流畅,但是需要处理的细节第一次没怎么处理好,花了很多…...
多线程基础 -概念、创建、等待、分离、终止
文章目录 一、 线程概念1. 什么是线程2. 线程的优点3.线程的缺点4. 线程异常5. 线程用途 二、 Linux进程VS线程1. 进程和线程2. 进程和线程的地址空间3. 进程和线程的关系 三、Linux线程控制1. POSIX线程库2. 线程创建3. 线程ID及进程地址空间布局4. 线程终止5. 线程等待6. 线程…...
【Vue3】走进Pinia,学习Pinia,使用Pinia
💗💗💗欢迎来到我的博客,你将找到有关如何使用技术解决问题的文章,也会找到某个技术的学习路线。无论你是何种职业,我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章,也欢…...
【TB作品】430单片机,单片机串口多功能通信,Proteus仿真
文章目录 题目功能仿真图程序介绍代码、仿真、原理图、PCB 题目 60、单片机串口多功能通信 基本要求: 设计一串口通信程序,波特率38400,通过RS232与PC机通信。 自动循环发送数据串(设计在程序中) 接收并存储和显示该数据串 在发送端定义10个ASCII码键0-9 按键发送单字节,PC机接…...
【C++ leetcode】双指针问题
1. 611. 有效三角形的个数 题目 给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。 题目链接 . - 力扣(LeetCode) 画图 和 文字 分析 判断是否是三角形要得到三边,由于遍历三边要套三层循环&#x…...
Kubernetes集群部署
1.集群环境搭建 1.1 环境规划 kubernetes集群大体上分为两类:一主多从和多主多从。 一主多从:一台Master节点和多台Node节点,搭建简单,但是有单机故障风险,适合用于测试环境多主多从:多台Master节点和多…...
深拷贝与浅拷贝
深拷贝与浅拷贝是在进行对象复制时常见的两种方式,这两个概念其实比较混淆,面试中也经常出现,但是实际开发很少用到,所以本文就来详细讲解一下,让大家不再迷惑。 浅拷贝只是复制了对象的引用(地址…...
golang学习网址
.1LearnKu 终身编程者的知识社区 https://learnku.com/...
别再死记硬背公式了!用Python模拟动画带你直观理解雷达的瑞利散射与米散射
用Python动画解密雷达散射:从瑞利到米氏的视觉之旅 当我在大学第一次接触雷达气象学时,那些关于散射理论的数学公式让我头疼不已——直到我发现用代码把它们变成会动的图像。本文将带你用Python重现这个"顿悟时刻",通过动态可视化理…...
3分钟快速诊断网络NAT类型:NatTypeTester完整指南
3分钟快速诊断网络NAT类型:NatTypeTester完整指南 【免费下载链接】NatTypeTester 测试当前网络的 NAT 类型(STUN) 项目地址: https://gitcode.com/gh_mirrors/na/NatTypeTester 你是否曾经遇到过在线游戏卡顿、视频会议断断续续&…...
《短剧平台商品详情页前端性能优化实战》
🎭 《短剧平台商品详情页前端性能优化实战》背景:短剧平台(如 ReelShort、河马剧场等)的商品详情页(PDP)本质是“内容即商品”。用户路径为:刷剧 → 遇到付费节点 → 购买整部剧/解锁单集。核心…...
CloudDrive实战:轻松将115网盘挂载为本地磁盘,享受无缝存储体验
1. 为什么需要将网盘挂载为本地磁盘? 每次打开网盘客户端才能上传下载文件,是不是觉得特别麻烦?想象一下,如果你的网盘能像电脑里的D盘、E盘一样直接出现在"此电脑"里,所有操作都跟本地文件一模一样…...
鸿蒙_使用组件导航Navigation搭建应用框架
组件导航封装了页面、标题、菜单栏、工具栏等功能,我们只需要进行简单的设置,就能快速搭建应用的框架,我们直接新建一个独立页面来通过组件导航实现主页、设置页、我的页三个示例页面,并且相互之间可以跳转,并且天然支…...
Neural Renderer实战:从3D模型到物理对抗样本的渲染流程解析
1. Neural Renderer与物理对抗攻击初探 第一次听说Neural Renderer能用于生成物理对抗样本时,我的反应和大多数开发者一样——既兴奋又困惑。兴奋的是这个技术能让3D模型在真实世界中"隐身",困惑的是具体实现路径。经过三个月的项目实践&#…...
如何用Illustrator脚本库在5分钟内完成设计自动化?提升22倍效率的完全指南
如何用Illustrator脚本库在5分钟内完成设计自动化?提升22倍效率的完全指南 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 你是否曾在Adobe Illustrator中花费数小时重复…...
基于STC89C52与ADC0832的智能浇花系统设计与实现(附完整工程)
1. 智能浇花系统设计背景与核心思路 养花爱好者最头疼的问题莫过于出差或旅行时植物无人照料。传统定时浇水方案无法感知土壤实际湿度,容易导致浇水不足或过度。我在三年前第一次尝试用STC89C52制作自动浇花装置时,就遇到过水泵频繁误启动把多肉植物淹死…...
Janus-Pro-7B企业知识管理:基于AI的文档智能检索与摘要
Janus-Pro-7B企业知识管理:基于AI的文档智能检索与摘要 你是不是也遇到过这种情况?公司服务器里堆满了产品手册、项目报告、会议纪要,想找个资料得翻半天,最后还不一定能找到。或者,一份几十页的技术文档摆在面前&…...
BiRefNet模型TensorRT终极加速指南:5步实现3倍推理速度提升
BiRefNet模型TensorRT终极加速指南:5步实现3倍推理速度提升 【免费下载链接】BiRefNet [CAAI AIR24] Bilateral Reference for High-Resolution Dichotomous Image Segmentation 项目地址: https://gitcode.com/gh_mirrors/bi/BiRefNet BiRefNet作为CAAI AIR…...
