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

C++ 条件变量:wait、wait_for、wait_until

前言

在C++中,条件变量(std::condition_variable)是用来在多个线程之间同步执行流的一种机制。它们通常与互斥锁(如std::mutex)一起使用,以在特定条件满足时唤醒一个或多个线程。条件变量有三种使线程阻塞并等待唤醒的方法,分别是waitwait_forwait_until三种方式,三种方式有不同的特点;

内容

Wait

  • 功能wait 函数使当前线程阻塞,直到另一个线程调用 notify_onenotify_all
  • 参数:它需要两个参数:一个 std::unique_lock<std::mutex>(或类似的锁类型),它应该在调用 wait 之前由调用线程锁定,并且在 wait 等待期间由 wait 自动解锁;以及一个函数或可调用对象(通常是一个lambda表达式或函数指针),用于检查条件是否满足。
  • 特点wait 会无限期地等待,直到条件满足。它会在每次从 wait 返回时重新获取互斥锁。
#include <mutex>
#include <condition_variable>
#include <thread> 

std::mutex mtx; 
std::condition_variable cv; 
bool ready = false; 

void print_id(int id) 
{ 
	std::unique_lock<std::mutex> lck(mtx); 
	while (!ready) 
	{
		cv.wait(lck); // 等待ready变为true 
	}
	// 当ready为true时,继续执行... 
	std::cout << "Thread " << id << '\n'; 
} 

void go() 
{ 
	std::unique_lock<std::mutex> lck(mtx); 
	ready = true; 
	cv.notify_all(); // 唤醒所有等待的线程 
} 

int main() 
{ 
	std::thread threads[10]; 
	// 创建10个线程 
	for (int i=0; i<10; ++i) 
	{
		threads[i] = std::thread(print_id, i);
	} 
	
	std::cout << "10 threads ready to race...\n";
	go(); // 唤醒所有线程 

	// 等待所有线程完成 
	for (auto& th : threads) 
	{
		th.join(); 
		return 0; 
	}
}

Wait_for

  • 功能wait_for 函数使当前线程阻塞一段指定的时间或直到另一个线程调用 notify_onenotify_all,以先发生者为准。
  • 参数:与 wait 类似,它需要一个 std::unique_lock<std::mutex> 和一个函数或可调用对象来检查条件。此外,它还需要一个表示等待时间的 std::chrono::duration 类型的参数。
  • 特点wait_for 提供了等待时间的上限。如果在指定的时间内条件没有变为真,则 wait_for 会返回,即使 notify_onenotify_all 还没有被调用。
#include <iostream> 
#include <thread> 
#include <mutex> 
#include <condition_variable> 
#include <chrono> 
std::mutex mtx; 
std::condition_variable cv; 
bool ready = false; 
void print_id(int id) 
{ 
	std::this_thread::sleep_for(std::chrono::seconds(1)); 
	std::cout << "Thread " << id << '\n'; 
} 
void print_ready() 
{ 
	std::unique_lock<std::mutex> lck(mtx); 
	while (!ready) 
	{ 
		// 循环直到条件满足 
		cv.wait_for(lck, std::chrono::seconds(2), []{ return ready; }); 
		// 等待直到ready为true或超时 
	} 
	std::cout << "Ready now\n"; 
} 

void go()
{ 
	std::unique_lock<std::mutex> lck(mtx); 
	ready = true; 
	cv.notify_one(); 
	// 唤醒一个等待的线程 
} 

int main() 
{ 
	std::thread threads[10]; 
	// 启动10个线程,它们将等待ready标志 
	for (int i = 0; i < 10; ++i) 
		threads[i] = std::thread(print_ready); 
	std::cout << "10 threads ready to race...\n";
	std::thread producer(go); 
	// 等待所有线程完成 
	for (auto& th : threads) 
		th.join(); 
	producer.join(); 
	return 0;
}

Wait_until

  • 功能wait_until 函数使当前线程阻塞直到指定的时间点或直到另一个线程调用 notify_onenotify_all,以先发生者为准。
  • 参数:与 waitwait_for 类似,它需要一个 std::unique_lock<std::mutex> 和一个函数或可调用对象来检查条件。此外,它还需要一个表示未来某个时间点的 std::chrono::time_point 类型的参数。
  • 特点wait_until 允许指定一个绝对的时间点作为等待的结束条件。如果在指定的时间点之前条件没有变为真,则 wait_until 会返回,即使 notify_onenotify_all 还没有被调用。
#include <iostream>  
#include <thread>  
#include <mutex>  
#include <condition_variable>  
#include <chrono>  
#include <system_clock>  
  
std::mutex mtx;  
std::condition_variable cv;  
bool ready = false;  

void print_id(int id, const std::string& threadName) {  
    // 模拟一些工作  
    std::this_thread::sleep_for(std::chrono::seconds(1));  
    std::cout << threadName << " " << id << std::endl;  
}  
  
void wait_for_ready(int id, const std::string& threadName) {  
    std::unique_lock<std::mutex> lck(mtx);  
    auto future_time = std::chrono::system_clock::now() + std::chrono::seconds(5); // 等待最多5秒  
  
    while (!ready) {  
        if (cv.wait_until(lck, future_time) == std::cv_status::timeout) {  
            std::cout << threadName << " " << id << " Timeout! Exiting.\n";  
            return;  
        }  
    }  
  
    // 如果ready为true,则继续执行  
    std::cout << threadName << " " << id << " Ready now.\n";  
    // 可以在这里处理数据...  
}  
  
void go() {  
    std::this_thread::sleep_for(std::chrono::seconds(3)); // 生产者准备数据需要一些时间  
  
    {  
        std::unique_lock<std::mutex> lck(mtx);  
        ready = true;  
        cv.notify_all(); // 唤醒所有等待的线程  
    }  
  
    // 生产者可以继续执行其他任务...  
}  
  
int main() {  
    std::thread threads[10];  
  
    // 启动10个消费者线程  
    for (int i = 0; i < 10; ++i) {  
        threads[i] = std::thread(wait_for_ready, i, "Consumer " + std::to_string(i+1));  
    }  
  
    std::thread producer(go);  
  
    // 等待所有消费者线程完成  
    for (auto& th : threads) {  
        th.join();  
    }  
  
    producer.join();  
  
    return 0;  
}

总结

  • wait:无限期等待直到条件满足。
  • wait_for:等待直到条件满足或指定的时间过去。
  • wait_until:等待直到条件满足或指定的时间点到达。

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

相关文章:

  • SQL面试题——蚂蚁SQL面试题 会话分组问题
  • 数据产品:深度探索与案例剖析
  • 408笔记合集
  • C++ 并发专题 - 自旋锁的实现(Spinlock)
  • 【大数据学习 | HBASE高级】rowkey的设计,hbase的预分区和压缩
  • 学习记录:js算法(九十二):克隆图
  • 【开源大模型生态9】百度的文心大模型
  • 主播和礼品检测系统源码分享
  • 高速下载大模型文件
  • 【读点论文】Text Recognition in the Wild: A Survey 非常纯粹的OCR研究,专业细致,脉络清晰
  • Datawhale X 南瓜书 task01学习笔记
  • Vue3(一) Vite创建Vue3工程,选项式API与组合式API;setup的使用;Vue中的响应式ref,reactive
  • c语言练习题1(数组和循环)
  • python发送邮件 - email smtplib
  • vue2项目实现国际化(若依框架示例)
  • c语言习题
  • JS领域的AI工程利器分享
  • Spring Cloud Gateway组件
  • 如何在 Spring Boot中更改默认端口
  • sql语法学习
  • 【HTTPS】对称加密和非对称加密
  • 【C++前缀和 状态压缩】2588. 统计美丽子数组数目|1696
  • Springboot使用ThreadPoolTaskScheduler轻量级多线程定时任务框架
  • 网传阿里云盘出现bug,可看到其他用户云盘图片
  • VideoFileClip 切割视频
  • C#往压缩包Zip文件的文件追加数据