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

C++ 并发专题 - 条件变量的使用

一:概述:

在 C++ 中,条件变量std::condition_variable)是一种用于线程间同步的机制,主要用于在多线程环境中让一个线程等待某个条件满足后再继续执行。条件变量通常配合互斥锁(std::mutex)使用,保证了在访问共享数据时不会发生竞态条件。

二:条件变量的用途:

条件变量用于在某个线程等待另一个线程满足特定条件时进行同步。这通常用于以下几种情况:

  • 生产者-消费者问题:当缓冲区为空时,消费者线程等待生产者线程生产数据;当缓冲区满时,生产者线程等待消费者线程消费数据。
  • 线程池:工作线程等待任务队列中有任务可处理。
  • 任务调度:线程等待其他线程完成某些前置任务。

三:条件变量的工作原理:

  1. 等待条件:线程可以在条件变量上等待,直到某个条件成立(例如,某个标志被设置)。
  2. 通知条件:当某个线程修改共享数据并满足条件时,它可以通过条件变量通知等待的线程,通常使用 notify_one()notify_all() 方法。

四:核心方法:

  • wait:让当前线程等待,直到满足指定条件。在调用 wait 时,条件变量会自动释放与之关联的互斥锁,等待条件满足后再重新获取锁。
  • notify_one:唤醒一个在条件变量上等待的线程。如果没有线程在等待,它什么也不做。
  • notify_all:唤醒所有在条件变量上等待的线程。

五:条件变量的使用注意事项:

  1. 避免虚假唤醒:条件变量的 wait 方法会有可能被虚假唤醒(即条件未改变时线程被唤醒)。因此,通常需要在 wait 语句中使用一个循环来检查条件:
    while (!condition) {
        cv.wait(lock);
    }
    
  2. 锁的管理wait 会释放互斥锁并进入休眠状态,直到被通知并且重新获得锁。使用 std::unique_lock 管理锁是推荐的做法,因为它支持锁的自动管理。
  3. notify_one vs notify_allnotify_one() 只会唤醒一个线程,而 notify_all() 会唤醒所有等待的线程。根据需要选择使用哪一个方法,通常只有一个线程需要继续时使用 notify_one(),而如果有多个线程依赖于同一条件时,则可能需要使用 notify_all()

六:示例

#include <condition_variable>
#include <iostream>
#include <thread>
#include <mutex>

bool dataReady = false; 

std::mutex mutex_;
std::condition_variable condVar1; 
std::condition_variable condVar2; 

int counter = 0;
int COUNTLIMIT = 50; 


void setTrue()
{
	while (counter <= COUNTLIMIT)
	{
		std::unique_lock<std::mutex> lck(mutex_);
		condVar1.wait(lck, [] {return dataReady == false; });
		dataReady = true; 
		++counter;
		std::cout << dataReady << '\n';
		condVar2.notify_one();
	}
}

void setFalse()
{
	while (counter <= COUNTLIMIT)  // 循环直到 counter 达到 COUNTLIMIT
	{
		std::unique_lock<std::mutex> lck(mutex_);  // 获取互斥锁,保护共享数据
		condVar2.wait(lck, [] {return dataReady == true; });  // 等待条件变量,直到 dataReady 为 true
		dataReady = false;  // 修改 dataReady 为 false
		std::cout << dataReady << '\n';  // 输出 dataReady 的值(即 false)
		condVar1.notify_one();  // 唤醒另一个线程,通知它继续执行
	}
}


int main()
{
	std::cout << std::boolalpha << '\n'; 
	std::cout << "Begin: " << dataReady << '\n'; 

	std::thread t1(setTrue);
	std::thread t2(setFalse);

	t1.join();
	t2.join();

	dataReady = false;

	std::cout << "End: " << dataReady << '\n';
	std::cout << '\n';

	return 0; 
}


http://www.kler.cn/a/383776.html

相关文章:

  • H7-TOOL的CAN/CANFD助手增加帧发送成功标识支持, 继续加强完善功能细节
  • 大模型应用编排工具Dify二开之工具和模型页面改造
  • Unity网络开发基础(part5.网络协议)
  • unity实习面
  • 【Python】怎么创建一个新的conda环境,并在其中安装所需的软件包
  • [Code]R2u_Net
  • 30个Python小游戏,初学者也能快乐敲代码啦(全部源码均可分享)
  • RabbitMQ 高级特性——消息分发
  • 11、文件系统和日志管理
  • uniapp radio单选
  • 15分钟学 Go 第 34 天:依赖管理——Go Modules
  • 25中海油笔试测评春招秋招校招暑期实习社招笔试入职测评行测题型微测网题型分享
  • 为什么Uptime+Kuma本地部署与远程使用是网站监控新选择?
  • 【360】基于springboot的志愿服务管理系统
  • sklearn 安装使用笔记
  • Spring底层源码(一)
  • 【Mac】PD报错:无法为“Windows” 完成操作,虚拟机ID无效的解决办法
  • 中科院二区idea:多尺度注意力+特征融合!把准11个创新套路,直通毕业!
  • 高级数据库 项目流程记录
  • Oracle 第21章:实时应用集群(RAC)
  • 梧桐数据库空间向量使用介绍分享
  • git的使用、router和route的区别以及v-show和v-if的差别
  • 基于Python+Vue开发的蛋糕商城管理系统
  • 定高虚拟列表:让大数据渲染变得轻松
  • 智慧城市的守护者——智能井盖监测终端
  • 微信小程序 uniapp网络记账设计个人理财系统