线程中的条件变量pthread_cond_t

条件变量不是锁,但通常结合锁使用,条件变量用于检查某个条件是否满足。

条件变量基本函数
int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr);// 动态初始化条件变量,参数cond:条件变量的指针,参数attr:条件变量的初始属性。成功返回0,失败错误号。
int pthread_cond_destory(pthread_cond_t *cond);// 销毁条件变量,参数cond:条件变量的指针。成功返回0,失败错误号。
int pthread_cond_signal(pthread_cond_t *cond);// 条件满足后,可以使用该函数通知至少一个线程条件已满足,线程收到通知后会被唤醒
int pthread_cond_broadcast(pthread_cond_t *cond);// 条件满足后广播通知所有线程。pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 静态初始化
pthread_cond_wait函数
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
// 阻塞式等待条件变量cond满足,阻塞的同时释放互斥量mutex,等到满足条件后,wait返回,同时对mutex加锁。成功返回0,失败错误号。

pthread_cond_wait函数中的阻塞式检查条件满足和释放互斥锁两个操作一起被作为一个原子操作。释放互斥锁后,解除阻塞,重新加锁。

pthread_cond_timewait函数
int pthread_cond_timewait(phthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); // 成功返回0,失败错误号

作用:在某个时间内阻塞式等待条件成立,若超时则条件不满足也返回并唤醒线程。

条件变量在生产者消费者模型中的应用:

在生产者消费者问题中,若缓冲区为空,则消费者无法消费,于是消费者线程应使用pthread_cond_wait阻塞式等待条件:缓冲区不为空满足。生产者生产一个产品后,缓冲区不为空条件满足,于是使用pthread_cond_signal唤醒之前由于缓冲区为空而被阻塞的消费者线程。

生产者消费者问题中,条件变量对应的互斥锁用于使各生产者、消费者互斥地访问临界资源(本例中即缓冲区)。

流程为:

消费者:

  1. 创建一个条件变量:pthread_cond_t cond 并初始化条件变量:pthread_cond_init -该操作是全局的
  2. 创建一个互斥锁:pthread_mutex_t mutex 并初始化互斥锁:pthread_mutex_init -该操作是全局的
  3. 加锁:pthread_mutex_lock;
  4. 消费者线程使用pthread_cond_wait阻塞式等待缓冲区不为空的条件发生,在wait函数中,若消费者线程阻塞,则wait会对互斥量mutex解锁,以使生产者线程得以访问缓冲区。注意:此时pthread_cond_wait函数并未结束,而是在阻塞中,等待生产者生产一个产品。

    -----pthread_cond_wait函数中阻塞与解锁作为一个原子操作是为了防止阻塞后立即被其他线程占领CPU但由于互斥锁未释放,缓冲区资源由于互斥锁无法被访问,而导致死锁的情况发生。
     
  5. 若消费者线程要访问的缓冲区为空,生产者线程生产一个产品放入缓冲区,使用pthread_cond_signal 唤醒刚刚进入阻塞的消费者线程。
  6. 若消费者线程要访问的缓冲区不为空,消费者线程直接被唤醒;
  7. 消费者线程的wait函数收到唤醒消息后,wait函数对缓冲区加锁(改mutex为加锁状态),之后,消费者线程访问共享数据(缓冲区)。
  8. 解锁pthread_mutex_unlock,释放条件变量pthread_cond_destory,释放锁pthread_mutex_destory。

生产者:

  1. 生产数据;
  2. 加锁pthread_mutex_lock;
  3. 将数据放入缓冲区;
  4. 解锁pthread_mutex_unlock,并通知阻塞中的消费者线程pthread_cond_signal/pthread_cond_boardcast。
  5. 循环生产后续数据.

程序示例1:
代码:
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<stdio.h>struct msg{struct msg *next;int num;
};struct msg *head;pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void* consumer(void* p){struct msg *mp;for(;;){pthread_mutex_lock(&lock);while(head == NULL){pthread_cond_wait(&has_product, &lock);}// 消费一个产品mp = head;head = mp->next;pthread_mutex_unlock(&lock);printf("-Consume %lu ---%d\n", pthread_self(), mp->num);free(mp);sleep(rand() % 5);}}void* producer(void* p){struct msg *mp;for(;;){mp = malloc(sizeof(struct msg));mp->num = rand() % 1000 + 1;printf("-Produce ----------------%d\n", mp->num);pthread_mutex_lock(&lock);mp->next = head;head = mp;pthread_mutex_unlock(&lock);pthread_cond_signal(&has_product);sleep(rand() % 5);}}int main(int argc, char *argv[]){pthread_t pid, cid;srand(time(NULL));for(int i = 0; i < 3; i++){pthread_create(&pid, NULL, producer, NULL);}for(int i = 0; i < 3; i++){pthread_create(&cid, NULL, consumer, NULL);}pthread_join(pid, NULL);pthread_join(cid, NULL);return 0;
}
执行结果:

程序示例2:
代码:
#include<pthread.h>const int BUFFER_MAXNUM = 3;pthread_cond_t empty_cond = PTHREAD_COND_INITIALIZER, full_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;int empty = BUFFER_MAXNUM, full = 0;int cnt = 0;void* productor(void* arg){while(1){pthread_mutex_lock(&mutex);--empty;if(empty < 0){printf("生产者%d 等待缓冲区不为满\n", (int)arg);pthread_cond_wait(&full_cond, &mutex);printf("生产者%d 已等到缓冲区不为满\n", (int)arg);}// 生产printf("生产者%d, product %dth\n", (int)arg, ++cnt);// 将数据放入缓冲区if(++full <= 0){pthread_cond_signal(&empty_cond);}pthread_mutex_unlock(&mutex);sleep(1);}
}void* consumer(void* arg){while(1){pthread_mutex_lock(&mutex);if(--full < 0){printf("消费者%d 等待缓冲区不为空\n", (int)arg);pthread_cond_wait(&empty_cond, &mutex);printf("消费者%d 已等到缓冲区不为空\n", (int)arg);}// 消费一个产品printf("消费者%d, cast %dth\n", (int)arg, cnt--);if(++empty <= 0){pthread_cond_signal(&full_cond);}pthread_mutex_unlock(&mutex);sleep(1);}
}int main(){pthread_t pdr, csr;for(int i = 0; i < 3; i++){pthread_create(&pdr, NULL, productor, (void*)i);}for(int i = 0; i < 5; i++){pthread_create(&csr, NULL, consumer, (void*)i);}pthread_exit(NULL);
}
执行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1546936.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Excel怎么自动排序?4种方法任君选择

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f522; 在处理大量数据时&#xff0c;保持数据的有序性是非常重要的。Excel提供了几种自动排序的方法&#xff0c;可以帮助我们快速地对数据进行排序&#xff0c;确保数据的组织和分析更加高效。今天&#xff0c;我们…

推荐几个前端组件库,真好用!

今天给大家推荐几款的后台管理系统开箱即用的组件库&#xff0c;基于ElementUI二次封装&#xff0c;开发必备 Headless UI Headless UI 是一款出色的前端组件库&#xff0c;专为与 Tailwind CSS 集成而设计。一组完全无样式、完全可访问的 UI 组件&#xff0c;可以自由的引入…

2024网站建设哪家公司比较好TOP3

在数字化时代&#xff0c;随着个人和商业活动越来越多地转移到线上&#xff0c;网站安全性的问题显得尤为重要。用户数据的保护是建立消费者信任和维护企业声誉的基石。靠谱的网站建设供应商深知这一点&#xff0c;他们把网站安全性作为开发过程中的首要考虑因素之一。 首先&a…

数据结构基础之《(5)—链表》

一、单向链表 1、单向链表节点结构&#xff08;可以实现成泛型&#xff09; public class Node{public int value;public Node next;public Node(int data) {value data;} } 2、双向链表节点结构 public class DoubleNode {public int value;public DoubleNode last;publi…

【Golang】Go语言中type关键字到底是什么?

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

FMEA实战指南:精准定参,筑牢产品质量防线

在FMEA分析中&#xff0c;严重度、频度和探测度三个参数的确定直接关系到风险顺序数(RPN)的计算&#xff0c;进而影响产品故障模式的优先排序和改进措施的制定。因此&#xff0c;掌握如何精准确定这些参数&#xff0c;对于提高产品质量、降低风险具有重要意义。深圳天行健企业管…

水面巡检船垃圾漂浮物检测系统源码分享

水面巡检船垃圾漂浮物检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of …

​初学者的自动化测试路线图:Playwright和TypeScript

测试对于确保软件运行良好非常重要。测试自动化通过使用特殊的工具和程序快速准确地进行测试使这变得更容易。这有助于检查软件是否完成了它应该做的事情、它的性能如何以及它是否可靠。 通过自动化重复测试任务&#xff0c;团队可以显着加快测试过程&#xff0c;扩大测试覆盖…

泛微OA提示信息换行

⭐️如果对你有用的话&#xff0c;希望可以点点赞&#xff0c;感谢了⭐️ WfForm.setTextFieldEmptyShowContent("field111", "格式模板&#xff1a;将顾客客诉原因文字描述清楚\n如&#xff1a;顾客因对美养师手法不满&#xff0c;觉得力度不够&#xff0c;没…

架构师:消息队列的技术指南

1、简述 消息队列(Message Queue, MQ)是一种异步通信机制,允许系统的各个组件通过消息在彼此之间进行通信。消息队列通过解耦系统组件、缓冲高峰期请求和提高系统的可扩展性,成为分布式系统中不可或缺的一部分。 2、工作原理 消息队列的基本工作原理是生产者将消息发布到…

远程办公生产力软件推荐,每天比同事早下班3个小时的秘密!

每天比同事早下班3个小时的秘密&#xff0c;终于被我找到啦&#xff01; 网易GameViewer远程是一款高效便捷的远程办公工具&#xff0c;支持多点触控、虚拟鼠标键盘、4K画质和低延迟。其隐私屏功能保护文件安全。 只需三步&#xff1a;安装、登录、远控&#xff0c;即可轻松提升…

Docker-2.如何保存数据退出

在使用Docker时&#xff0c;我们常常需要修改容器中的文件&#xff0c;并且希望在容器重启后这些修改能够得到保留。 0.简介 使用Docker时有一个需要注意的问题&#xff1a;当你修改了容器中的文件后&#xff0c;重启容器后这些修改将会被重置&#xff0c;深入研究这个问题。 …

远程访问软路由

远程访问软路由主要涉及通过互联网从远程位置访问和控制基于软件的路由器系统。以下是远程访问软路由的一般方法&#xff1a; 一、远程访问软路由的方法 通过Web管理界面访问&#xff1a; 适用于大多数支持Web管理的软路由系统。用户只需在浏览器中输入软路由的公网IP地址或域…

react中的ref三种形式

1&#xff0c;字符串形式 <!-- 创建盒子 --><div id"test"></div> <script type"text/babel">class Demo extends React.Component{render(){return(<div><input type"text" refinput1 /><button onCl…

从销售到 AI 算法工程师 | 转行人工智能大模型(含面经裁员幸存指南)

我叫王东&#xff0c;90后&#xff0c;和大家分享一下我的人工智能转型之路。 农学毕业&#xff0c;投身互联网做销售 机遇难求&#xff0c;养殖梦碎 我是土生土长的农村人&#xff0c;小时候经常和小鱼小虾打交道&#xff0c;上大学的时候就选择了农学专业&#xff0c;想着…

OpenKylin--解压文件

tar zxf dotnet-sdk-6.0.425-linux-x64.tar.gzrootsanzk-pc:/home/dotnet# tar zxf dotnet-sdk-6.0.425-linux-x64.tar.gz参考&#xff1a; rootxxx-pc:/home/xxx# mkdir -p /home/dotnet && tar zxf dotnet-sdk-6.0.411-linux-x64.tar.gz -C /home/dotnet mkdir -p /…

STM32F1+HAL库+FreeTOTS学习13——二值信号量

STM32F1HAL库FreeTOTS学习13——二值信号量 1. 信号量2. 二值信号量3. 相关API函数3.1 创建二值信号量3.2 获取信号量3.3 释放信号量3.4 删除信号量 4. 二值信号量操作实验1. 实验内容2. 代码实现&#xff1a;3. 运行结果 上一期我们学习了FreeRTOS中的队列&#xff0c;这一期我…

【含文档】基于Springboot+Vue的高校失物招领平台(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

Excel中用位置筛选解法

有 2022 年 1 月的日销售额统计表如下所示&#xff1a; 筛选出偶数日的销售额&#xff1a; spl("E(?1).select(#%20)",A1:B32)#表示当前行号 免费课程、软件免费下载

免杀笔记 ---> 无痕Hook?硬件断点 Syscall!

说到Hook&#xff0c;我们有很多Hook&#xff0c;像Inline-Hook&#xff0c;我们也是用的比较多&#xff0c;但是正如我上一篇Blog说的&#xff0c;他会对内存进行修改&#xff0c;如果EDR或者AV增加一个校验机制&#xff0c;不断检验某一块内存&#xff0c;那么就算你用syscal…