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.mfbz.cn/a/881834.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode - 139双周赛

目录 一&#xff0c;3285. 找到稳定山的下标 二&#xff0c;3286. 穿越网格图的安全路径 三&#xff0c;3287. 求出数组中最大序列值 四&#xff0c;3288. 最长上升路径的长度 一&#xff0c;3285. 找到稳定山的下标 本题就是找[0&#xff0c; n-2]中&#xff0c;height[i]…

升级你的HarmonyOS体验:一窥功能引导与拖拽交换的独家技巧

文章目录 前言项目目录结构开发流程主要步骤讲解关键配置Index.ets 页面讲解高光组件相关HeaderApp 总结 前言 在当今的移动应用开发领域&#xff0c;为了提供更加友好和直观的用户体验&#xff0c;开发者们通常会集成多种交互功能来增强应用的互动性和易用性。在这些功能中&a…

故障诊断│GWO-DBN灰狼算法优化深度置信网络故障诊断

1.引言 随着人工智能技术的快速发展&#xff0c;深度学习已经成为解决复杂问题的热门方法之一。深度置信网络&#xff08;DBN&#xff09;作为深度学习中应用比较广泛的一种算法&#xff0c;被广泛应用于分类和回归预测等问题中。然而&#xff0c;DBN的训练过程通常需要大量的…

go 读取excel数据存储到mysql

一、安装依赖 go get github.com/go-sql-driver/mysql go get github.com/jmoiron/sqlx 二、main.go package mainimport ("fmt""github.com/jmoiron/sqlx""log" ) import "github.com/tealeg/xlsx" import _ "github.com/go-s…

【LeetCode热题100】位运算

这篇博客先介绍了常见位运算操作&#xff0c;然后记录了关于位运算的几道题&#xff0c;包括判定字符是否唯一、丢失的数字、两整数之和、只出现一次的数字2、消失的两个数字。 在这一部分&#xff0c;我们不妨先来总结一下常见位运算操作&#xff1a; 1.基础位运算 >>…

C++——模拟实现string

1.再谈string string为什么要被设计成模板&#xff1f;日常使用string好像都是char*&#xff0c;char*不够使用吗&#xff0c;为什么要设计成模板呢&#xff1f; 1.1 关于编码 //计算机的存储如何区分呢&#xff1f;int main() {//比如在C语言中&#xff0c;有整型//如果是有…

craco-less使用问题

craco-less使用问题 问题背景 前端是用React搭建&#xff0c;使用craco配置&#xff0c;相关库或插件版本如下 "craco/craco": "^7.1.0","react-scripts": "^5.0.1","craco-less": "^3.0.1"在生产环境&#xff…

P9235 [蓝桥杯 2023 省 A] 网络稳定性

*原题链接* 最小瓶颈生成树题&#xff0c;和货车运输完全一样。 先简化题意&#xff0c; 次询问&#xff0c;每次给出 &#xff0c;问 到 的所有路径集合中&#xff0c;最小边权的最大值。 对于这种题可以用kruskal生成树来做&#xff0c;也可以用倍增来写&#xff0c;但不…

国内可以使用的ChatGPT服务【9月持续更新】

首先基础知识还是要介绍得~ 一、模型知识&#xff1a; GPT-4o&#xff1a;最新的版本模型&#xff0c;支持视觉等多模态&#xff0c;OpenAI 文档中已经更新了 GPT-4o 的介绍&#xff1a;128k 上下文&#xff0c;训练截止 2023 年 10 月&#xff08;作为对比&#xff0c;GPT-4…

SSM+vue音乐播放器管理系统

音乐播放器管理系统 随着社会的发展&#xff0c;计算机的优势和普及使得音乐播放器管理系统的开发成为必需。音乐播放器管理系统主要是借助计算机&#xff0c;通过对首页、音乐推荐、付费音乐、论坛信息、个人中心、后台管理等信息进行管理。减少管理员的工作&#xff0c;同时…

2024短剧系统开发,付费短剧小程序app源码教程,分销功能讲解搭建上线

短剧系统技术栈 前端&#xff1a;vue3uniapp 后端&#xff1a; php 数据库&#xff1a;mysql 服务器环境&#xff1a; centos7.6 宝塔 php7.4 MySQL5.7 一、短剧系统功能 短剧用户端&#xff1a; 小程序、抖音小程序、快手小程序、APP、 z付宝小程序 系统用户端详细功能&…

有关shell指令练习2

写一个shell脚本&#xff0c;将以下内容放到脚本中 在家目录下创建目录文件&#xff0c;dir dir下创建dir1和dir2 把当前目录下的所有文件拷贝到dir1中&#xff0c; 把当前目录下的所有脚本文件拷贝到dir2中 把dir2打包并压缩为dir2.tar.xz 再把dir2.tar.xz移动到dir1中 …

ABAP-Swagger 一种公开 ABAP REST 服务的方法

ABAP-Swagger An approach to expose ABAP REST services 一种公开 ABAP REST 服务的方法 Usage 1: develop a class in ABAP with public methods 2: implement interface ZIF_SWAG_HANDLER, and register the public methods(example method zif_swag_handler~meta) 3: …

nonlocal本质讲解(前篇)——从滤波到Nonlocal均值滤波

线性滤波 → \rightarrow →高斯滤波 → \rightarrow →高斯滤波 → \rightarrow →双边滤波 → \rightarrow →Nonlocal均值滤波 平均 高斯 双边 Nonlocal 目录 线性滤波高斯滤波双边滤波Nonlocal均值滤波 滤波最初是频域的概念&#xff0c;由于频域乘积对应空域卷积&am…

药物分子生成算法综述:从生成对抗网络到变换器模型的多样化选择

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 基于已有的药物数据生成新的药物分子是一项复杂的任务&#xff0c;通常涉及到生成模型和机器学习算法。以下是一些常用的算法和方法&#xff1a; 1. 生成对抗网络 (GANs) 特点: 由生成…

罗马数字详解

一. 罗马数字の背景 1. 罗马数字的诞生与进化 罗马数字起源于古罗马帝国&#xff0c;拥有一个漫长而复杂的历史&#xff0c;始于公元前 8 世纪至 9 世纪&#xff0c;与古罗马帝国在帕兰丁山&#xff08;Palantine Hill&#xff09;周围建立的时间大致相同。不过&#xff0c;罗…

【GUI设计】基于Matlab的图像处理GUI系统(2),matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于Matlab的图像处理GUI系统&#xff08;2&#xff09;&#xff0c;用matlab实现。…

jboss

一。CVE-2015-7501 1.POC&#xff0c;访问地址 192.168.10.193:8080/invoker/JMXInvokerServlet 返回如下&#xff0c;说明接⼝开放&#xff0c;此接⼝存在反序列化漏洞 2.下载 ysoserial ⼯具进⾏漏洞利⽤ https://github.com/frohoff/ysoserial 将反弹shell进⾏base64编码…

java重点学习-设计模式

十三 设计模式 工厂模式&#xff1a;spring中使用&#xff08;目的是&#xff1a;解耦&#xff09; 1.简单工厂 所有的产品都共有一个工厂&#xff0c;如果新增产品&#xff0c;则需要修改代码&#xff0c;违反开闭原则是一种编程习惯&#xff0c;可以借鉴这种编程思路 2.工厂方…

基于SpringBoot+WebSocket实现地图上绘制车辆实时运动轨迹图

实现基于北斗卫星的车辆定位和轨迹图的Maven工程&#xff08;使用模拟数据&#xff09;&#xff0c;我们将使用以下技术&#xff1a; Spring Boot&#xff1a;作为后端框架&#xff0c;用来提供数据接口。Thymeleaf&#xff1a;作为前端模板引擎&#xff0c;呈现网页。Leaflet…