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

news/2024/9/19 21:17:54 标签: c++, 开发语言

前言

在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.niftyadmin.cn/n/5666155.html

相关文章

设计模式之命令模式:从原理到实战,深入解析及源码应用

&#x1f3af; 设计模式专栏&#xff0c;持续更新中 欢迎订阅&#xff1a;JAVA实现设计模式 &#x1f6e0;️ 希望小伙伴们一键三连&#xff0c;有问题私信都会回复&#xff0c;或者在评论区直接发言 命令模式 什么是命令模式&#xff1f; 命令模式&#xff08;Command Pattern…

从黎巴嫩电子通信设备爆炸看如何防范网络电子袭击

引言&#xff1a; 在当今数字化时代&#xff0c;电子通信设备已成为我们日常生活中不可或缺的一部分。然而&#xff0c;近期黎巴嫩发生的电子设备爆炸事件提醒我们&#xff0c;这些设备也可能成为危险的武器。本文将深入探讨电子袭击的原理、防范措施&#xff0c;以及网络智能…

自学网络安全(黑客技术)_90天速成法

&#x1f91f; 基于入门网络安全/黑客打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 一、什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“…

Laya2.x出包alipay小游戏

小游戏开发者工具&#xff0c;支付宝官方已经出了&#xff0c;不说了。 1.LAYA2.X打出得小游戏包中my-adapter.js这个文件需要替换&#xff0c;或者自行修改&#xff0c;替换3.x得&#xff1b; 2.unity导包出得模型文件命名需要注意&#xff0c;避免太长&#xff0c;路径也不…

【ShuQiHere】 支持向量机(SVM)详解:从理论到实践,这一篇就够了

&#x1f4d6; 【ShuQiHere】 在现代机器学习课程中&#xff0c;支持向量机&#xff08;SVM&#xff09; 是不可或缺的一部分。它不仅在分类任务中有出色表现&#xff0c;还能灵活处理回归问题。尽管看似复杂&#xff0c;SVM 背后的思想却深刻而优雅。今天我们将全面探讨**支持…

使用Docker安装 Skywalking(单机版)

使用Docker安装 Skywalking&#xff08;单机版&#xff09; 文章目录 使用Docker安装 Skywalking&#xff08;单机版&#xff09;Skywalking 介绍Skywalking 安装 Skywalking 介绍 Skywalking官网 分布式系统的应用程序性能监视工具&#xff0c;专为微服务、云原生架构和基于容…

【Unity】检测鼠标点击位置是否有2D对象

在这里提供两种方案&#xff0c;一种是射线检测&#xff0c;另一种是非射线检测。 初始准备步骤&#xff1a; 创建2D对象&#xff08;比如2D精灵&#xff09;给要被检测的2D对象添加2D碰撞体&#xff08;必须是2D碰撞体&#xff09;创建一个空对象&#xff0c;再创建一个检测…

简单题35-搜索插入位置(Java and Python)20240919

问题描述&#xff1a; Java&#xff1a; class Solution {public int searchInsert(int[] nums, int target) {int k 0;int i 0;while(i<nums.length){if(nums[i]target){return i;}if(nums[i]<target){k i1;}i;}return k;}}class Solution(object):def searchInsert(…