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.rhkb.cn/news/429576.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Why is OpenAI image generation Api returning 400 bad request in Unity?

题意&#xff1a;为什么 OpenAI 图像生成 API 在 Unity 中返回 400 Bad Request 错误&#xff1f; 问题背景&#xff1a; Im testing out dynamically generating images using OpenAI API in Unity. Amusingly, I actually generated most of this code from chatGPT. 我正在…

【笔记】第二节 轧制、热处理和焊接工艺

2.2 钢轨的轧制工艺 坯料进厂按标准验收, 然后装加热炉加热, 加热好的钢坯经高压水除鳞后进行轧制。轧出的钢轨经锯切、打印到中央冷床冷却, 然后装缓冷坑进行缓冷。缓冷后的钢轨进行矫直、轨端加工和端头淬火。钢轨入库前逐根进行探伤和外观检查。 钢轨的轧制 #mermaid-svg-…

foreach,for in和for of的区别

forEach 不能使用break return 结束并退出循环 for in 和 for of 可以使用break return&#xff1b; for in 遍历的是数组的索引&#xff08;即键名&#xff09;&#xff0c;而for of遍历的是数组元素值。 for of 遍历的只是数组内的元素&#xff0c;而不包括数组的原型属性…

后端-navicat查找语句(单表与多表)

表格字段设置如图 语句&#xff1a; 1.输出 1.输出name和age列 SELECT name,age from student 1.2.全部输出 select * from student 2.where子语句 1.运算符&#xff1a; 等于 >大于 >大于等于 <小于 <小于等于 ! <>不等于 select * from stude…

JdbcTemplate常用方法一览AG网页参数绑定与数据寻址实操

JdbcTemplate是Spring框架中的一个重要组件&#xff0c;主要用于简化JDBC数据库操作。它提供了许多常用的方法&#xff0c;如查询、插入、更新、删除等。本文将介绍JdbcTemplate的常用方法及其使用方式&#xff0c;以及参数绑定和删除数据的方法。 一、JdbcTemplate常用方法 查…

钉钉与MySQL对接集成获取部门列表2.0打通EXECUTE语句

钉钉与MySQL对接集成获取部门列表2.0打通EXECUTE语句 接入系统&#xff1a;钉钉 钉钉是阿里巴巴集团打造的企业级智能移动办公平台&#xff0c;是数字经济时代的企业组织协同办公和应用开发平台。钉钉将IM即时沟通、钉钉文档、钉闪会、钉盘、Teambition、OA审批、智能人事、钉工…

828华为云征文|华为Flexus云服务器搭建Cloudreve私人网盘

一、华为云 Flexus X 实例&#xff1a;开启高效云服务新篇&#x1f31f; 在云计算的广阔领域中&#xff0c;资源的灵活配置与卓越性能犹如璀璨星辰般闪耀。华为云 Flexus X 实例恰似一颗最为耀眼的新星&#xff0c;将云服务器技术推向了崭新的高度。 华为云 Flexus X 实例基于…

基于SpringBoot+Vue的商城积分系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目源码、Python精…

我的AI工具箱Tauri版-MicrosoftTTS文本转语音

本教程基于自研的AI工具箱Tauri版进行MicrosoftTTS文本转语音服务。 MicrosoftTTS文本转语音服务 是自研的AI工具箱Tauri版中的一款功能模块&#xff0c;专为实现高效的文本转语音操作而设计。通过集成微软TTS服务&#xff0c;用户可以将大量文本自动转换为自然流畅的语音文件…

物理学基础精解【9】

文章目录 直线与二元一次方程两直线夹角直线方程斜率两点式方程截距式方程将不同形式的直线方程转换为截距方程直线的一般方程直线一般方程的系数有一个或两个为零的直线 参考文献 直线与二元一次方程 两直线夹角 两直线 y 1 k 1 x b 1 , y 2 k 2 x b 2 形成夹角 a 1 和 a…

关于字节 c++

字节的介绍 字节是计算机中最小的存储单位&#xff0c;通常由8个二进制位组成&#xff0c;用来存储一个字符。在C中&#xff0c;字节也是基本数据类型之一&#xff0c;用关键字"byte"来表示。字节主要用于存储一些较小的数据&#xff0c;如整数、字符等。字节的大小…

【Delphi】通过 LiveBindings Designer 链接控件示例

本教程展示了如何使用 LiveBindings Designer 可视化地创建控件之间的 LiveBindings&#xff0c;以便创建只需很少或无需源代码的应用程序。 在本教程中&#xff0c;您将创建一个高清多设备应用程序&#xff0c;该应用程序使用 LiveBindings 绑定多个对象&#xff0c;以更改圆…

python - self 调用父类方法

Python 子类继承父类构造函数说明 | 菜鸟教程如果在子类中需要父类的构造方法就需要显式地调用父类的构造方法&#xff0c;或者不重写父类的构造方法。 子类不重写 __init__&#xff0c;实例化子类时&#xff0c;会自动调用父类定义的 __init__。 实例 [mycode3 typepython] cl…

Linux基础---13三剑客及正则表达式

一.划水阶段 首先我们先来一个三剑客与正则表达式混合使用的简单示例&#xff0c;大致了解是个啥玩意儿。下面我来演示一下如何查询登录失败的ip地址及次数。 1.首先&#xff0c;进入到 /var/log目录下 cd /var/log效果如下 2.最后&#xff0c;输入如下指令即可查看&#xf…

基于协同过滤+python+django+vue的音乐推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于协同过滤pythondjangovue…

Linux使用常见问题指南

普通用户sudo权限问题 我在普通用户Sun下,编写了一个.cc文件,然后用sudo权限安装gcc/g去运行该文件,却提示我如下: 原因 当前的用户没有加入到sudo的配置文件里 #切换到root用户 su #编辑配置文件 vim /etc/sudoers #增加配置, 在打开的配置文件中&#xff0c;找到root ALL(A…

【iOS】ViewController的生命周期

相关函数 init: 初始化ViewController。viewDidLoad:在我之前学习中最多使用的方法&#xff0c;在创建类后无论视图展示还是消失&#xff0c;该方法只调用一次在布局中&#xff0c;类成员对象和变量的初始化都会放在这个方法中。viewWilAppear:如同英语含义一样&#xff0c;在…

Java设计模式—面向对象设计原则(五) ----->迪米特法则(DP) (完整详解,附有代码+案例)

文章目录 3.5 迪米特法则(DP)3.5.1 概述3.5.2 案例 3.5 迪米特法则(DP) 迪米特法则&#xff1a;Demeter Principle&#xff0c;简称DP 3.5.1 概述 只和你的直接朋友交谈&#xff0c;不跟“陌生人”说话&#xff08;Talk only to your immediate friends and not to stranger…

Springboot与minio

一、介绍 Minio是一个简单易用的云存储服务&#xff0c;它让你可以轻松地把文件上传到互联网上&#xff0c;这样无论你在哪里&#xff0c;只要有网络&#xff0c;就能访问或分享这些文件。如果你想要从这个仓库里取出一张图片或一段视频&#xff0c;让网站的访客能看到或者下载…

面向对象程序设计——set容器の简析

1.set的介绍 • 序列式容器和关联式容器 • 我们已经接触过STL中的部分容器如&#xff1a;string、vector、list、deque、array、forward_list等&#xff0c;这些容器统称为序列式容器&#xff0c;因为逻辑结构为线性序列的数据结构&#xff0c;两个位置存储的值之间⼀般没有紧…