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

线程同步:条件变量实战指南

目录

1.条件变量的概念:

2.条件变量的使用

3.例子


锁有可能导致某一线程独占资源的情况。例如下面写的一个抢票程序,其中一个线程ID为820427008的线程在竞争锁时,频繁且快速的获得了锁,由于调度器的调度时机等因素,始终抢不过这个线程,导致这个线程能够持续获取锁,从而表现出独占资源的现象

#include <pthread.h>
#include <cstdio>#define NUM 5pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int ticket = 100;void* get_ticket(void *args)//抢票
{pthread_detach(pthread_self());while(1){pthread_mutex_lock(&lock);if(ticket > 0)ticket--;else{pthread_mutex_unlock(&lock);break;}printf("%d :snap up ticket\n",pthread_self());pthread_mutex_unlock(&lock);}
}int main()
{for(int i = 0;i < NUM; i++){pthread_t pid;pthread_create(&pid,nullptr,get_ticket,nullptr);}pthread_mutex_destroy(&lock);return 0;
}

1.条件变量的概念:

条件变量是线程可用的另一种同步机制。当与互斥量一起使用时,条件变量允许线程以无竞争的方式等待任意条件的发生。

条件本身受互斥量保护的。线程必须首先锁定互斥量才能改变条件的状态。其他线程在锁定互斥量之前不会注意到这种变化,因为必须锁定互斥量才能评估

2.条件变量的使用

  1. 创建一个pthread_cond_t的数据
  2. 进行初始化,可以常量PTHREAD_COND_INITIALIZER赋值,也可以使用pthread_cond_init函数对其进行初始化
  3. 使用pthread_cond_wait函数。传递给pthread_cond_wait函数的互斥量会保护条件。调用者将其锁定的互斥量传递给函数,然后该函数自动将此调用线程方式等待条件的线程列表中,并解锁互斥量。
  4. 陷入pthread_cond_wait阻塞的函数,等待被pthread_cond_signal或broadcast唤醒
  5. 程序运行结束后,调用pthread_cond_destroy销毁条件变量

用图解方式解释一下在pthread_cond_wait“睡眠”的线程

注意:如果是调用pthread_cond_broadcast唤醒所有线程 一定要用while来循环判断 不然会使得多个线程都同时访问独立资源了,锁就失去意义。

3.例子

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>#define BUFFER_SIZE 5// 缓冲区结构
typedef struct {int buffer[BUFFER_SIZE];int in;  // 生产者放入数据的位置int out; // 消费者取出数据的位置int count; // 缓冲区中数据的数量
} Buffer;Buffer buffer;
// 互斥锁
pthread_mutex_t mutex;
// 条件变量:缓冲区不为空(供消费者等待)
pthread_cond_t cond_not_empty;
// 条件变量:缓冲区不为满(供生产者等待)
pthread_cond_t cond_not_full;// 生产者线程函数
void* producer(void* arg) {int item, i = 0;while (1) {item = i++;// 获取互斥锁,保护临界区pthread_mutex_lock(&mutex);// 当缓冲区满时,生产者等待while (buffer.count == BUFFER_SIZE) {printf("缓冲区满,生产者等待...\n");// 等待条件变量cond_not_full,同时释放互斥锁,让其他线程(如消费者)可以操作pthread_cond_wait(&cond_not_full, &mutex);}// 生产数据,放入缓冲区buffer.buffer[buffer.in] = item;buffer.in = (buffer.in + 1) % BUFFER_SIZE;buffer.count++;printf("生产者生产了数据:%d,当前缓冲区数据量:%d\n", item, buffer.count);// 通知消费者,缓冲区不为空了pthread_cond_signal(&cond_not_empty);// 释放互斥锁pthread_mutex_unlock(&mutex);// 模拟生产耗时usleep(rand() % 1000000);}return NULL;
}// 消费者线程函数
void* consumer(void* arg) {int item;while (1) {// 获取互斥锁,保护临界区pthread_mutex_lock(&mutex);// 当缓冲区空时,消费者等待while (buffer.count == 0) {printf("缓冲区空,消费者等待...\n");// 等待条件变量cond_not_empty,同时释放互斥锁,让其他线程(如生产者)可以操作pthread_cond_wait(&cond_not_empty, &mutex);}// 从缓冲区取出数据item = buffer.buffer[buffer.out];buffer.out = (buffer.out + 1) % BUFFER_SIZE;buffer.count--;printf("消费者消费了数据:%d,当前缓冲区数据量:%d\n", item, buffer.count);// 通知生产者,缓冲区不为满了pthread_cond_signal(&cond_not_full);// 释放互斥锁pthread_mutex_unlock(&mutex);// 模拟消费耗时usleep(rand() % 1000000);}return NULL;
}int main() {pthread_t producer_thread, consumer_thread;// 初始化缓冲区buffer.in = 0;buffer.out = 0;buffer.count = 0;// 初始化互斥锁和条件变量pthread_mutex_init(&mutex, NULL);pthread_cond_init(&cond_not_empty, NULL);pthread_cond_init(&cond_not_full, NULL);// 创建生产者和消费者线程pthread_create(&producer_thread, NULL, producer, NULL);pthread_create(&consumer_thread, NULL, consumer, NULL);// 等待线程结束(实际中可能需要更合理的退出机制)pthread_join(producer_thread, NULL);pthread_join(consumer_thread, NULL);// 销毁互斥锁和条件变量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond_not_empty);pthread_cond_destroy(&cond_not_full);return 0;
}


文章转载自:

http://u3vJcmxs.ysbrz.cn
http://vPVcy0e4.ysbrz.cn
http://2tMtXzXm.ysbrz.cn
http://iH5OuW03.ysbrz.cn
http://Jl9LCZK5.ysbrz.cn
http://3IBu905g.ysbrz.cn
http://KA1WlD8I.ysbrz.cn
http://59bTMG2T.ysbrz.cn
http://jEm6kjLz.ysbrz.cn
http://WXkElz2D.ysbrz.cn
http://HicHa9WW.ysbrz.cn
http://JcWrEyMt.ysbrz.cn
http://zf25cLZX.ysbrz.cn
http://t78T3WNS.ysbrz.cn
http://hPex94S7.ysbrz.cn
http://yiR4FuAc.ysbrz.cn
http://thdaD6Qz.ysbrz.cn
http://pQCmCknw.ysbrz.cn
http://v8H9tnl1.ysbrz.cn
http://yZDAfkoI.ysbrz.cn
http://TxJtQvaC.ysbrz.cn
http://Qml5gp8L.ysbrz.cn
http://7Lwq6CnC.ysbrz.cn
http://XBuyNjhn.ysbrz.cn
http://t1nJvnMN.ysbrz.cn
http://KtpazmOY.ysbrz.cn
http://ZRkYaolu.ysbrz.cn
http://DJH6sKPH.ysbrz.cn
http://LVGCEgzf.ysbrz.cn
http://yr4dNa2P.ysbrz.cn
http://www.dtcms.com/a/379429.html

相关文章:

  • OpenLayers数据源集成 -- 章节七:高德地图集成详解
  • AI助推下半年旺季,阿里国际站9月采购节超预期爆发
  • 电商平台拍立淘API接口调用全解析(基于淘宝/唯品会技术实践)
  • 9.11 Qt
  • 字节一面 面经(补充版)
  • 第二章 ELK安装部署与环境配置
  • I2C 总线
  • 设计模式——七大常见设计原则
  • 请创建一个视觉精美、交互流畅的进阶版贪吃蛇游戏
  • 利用美团龙猫添加xlsx的sheet.xml读取sharedStrings.xml中共享字符串输出到csv功能
  • 时序数据库:定义与基本特点
  • 【WorkManager】Android 后台任务调度的核心组件指南
  • python项目批量安装包和生成requirements.txt文件
  • 零部件力学测试系统参数
  • 3D Web轻量引擎HOOPS赋能BIM/工程施工:实现超大模型的轻量化加载与高效浏览!
  • Java Web应用的安全性与防护措施!
  • 填写简历信息
  • 优先算法——专题十一:字符串
  • [Spring Cloud][3]从零开始简单工程搭建实践详解,远程调用
  • 为什么要显示调用析构函数
  • MySQL 数据完整性与约束:从基础到实战,守护数据准确性
  • Python中的“占位符”艺术:深入理解pass关键字的妙用
  • 构建企业级Python离线包仓库:从下载到服务部署全流程指南
  • C++面向对象之多态
  • 个人自留笔记——git操作
  • 命令模式,餐厅订单管理系统C++
  • Android EDLA测试命令总结
  • opencv基础实践;银行卡号识别
  • 【录屏软件】 实用工具推荐——电脑录屏软件班迪(Bandicam)录屏图文安装指南
  • 微服务事务管理实践与 Seata 框架解析