当前位置: 首页 > 编程日记 > 正文

C++ 多线程:条件变量 std::condition_variable

文章目录

      • 描述
      • 使用

描述

  • 头文件<condition_variable>

  • 定义 class condition_variable;

  • 简介
    之前我们也已经介绍过了C++多线程中互斥变量存在,已经足够支持多线程中对共享普通系统数据的合理访问。但是因为多线程中同一时刻必然会有一个线程持有锁,一个线程等待锁。而在代码中使用while方式的循环等待必然会导致系统效率降低,cpu被无用消耗。
    查看如下代码

    #include <iostream>
    #include <thread>
    #include <string>
    #include <mutex>
    #include <deque> //包含deque的头文件
    using namespace std;std::mutex mu;
    std::deque<int> q; //全局共享数据,双端队列void function_1(){int count = 100;while (count > 0) {std::unique_lock<std::mutex> locker(mu);q.push_back(count);locker.unlock();std::this_thread::sleep_for(std::chrono::seconds(1));count--;}
    }void function_2() {int data = 0;while (data != 1) {std::unique_lock<std::mutex> locker(mu);//获取到锁之后检测全局共享队列是否为空,如果不为空则执行出队操作if (!q.empty()) { data=q.back();q.pop_back();locker.unlock();std::cout << "t2 got a value from t1 " << data << std::endl; } else {//如果为空,则尝试解锁locker.unlock();//防止消耗cpu//std::this_thread::sleep_for(std::chrono::seconds(1)); }}
    }
    int main()
    {std::thread t1(function_1);std::thread t2(function_2);t1.join();t2.join();return 0;
    }
    

    由以上代码可以很明显得看出来t1线程提供数据push_back(生产者),t2线程消费数据pop_back(消费者),这两个线程最合理得运行方式应该为生产者生产好数据,然后唤醒消费者去消费,消费完成之后继续休眠。

    但是在t2线程如果检测到全局队列为空,则会尝试解锁,但是在t1线程向全局队列push数据的时候t2线程仍然在尝试解锁,这样的操作会导致系统cpu资源被无端消耗,即消费者一直在等待着生产者生产。
    这个时候我们的条件变量即可出山,它能够比sleep_for函数使用起来更灵活

使用

在解决以上问题之前,先介绍几个条件变量包含的成员函数

  • std::condition_variable::notify_onestd::condition_variable::notify_one通知一个等待线程,同时改函数作用在当前条件变量上
  • std::condition_variable::wait()导致当前线程阻塞直至条件变量被通知
    wait( std::unique_lock<std::mutex>)函数的实现方式是先原子解锁线程,将当前线程加入到线程的等待执行列表,当notify_one或者notify_all解锁阻塞线程之后,等待列表中的线程继续执行完毕,并重新加锁,最后退出wait()
    调用此函数之前必须保证当前函数已经被锁定,且这里使用的锁需为unique_lock,因为只有unique_lock才能够支持同一个线程的重复加解锁。
  • std::condition_variable::wait_for它的等待方式和wait的区别是增加了一个等待的时间,即除了等待notify_one解锁之外还会有一个时间阈值,当到了这个时间阈值时仍然会退出。wait_for( std::unique_lock<std::mutex>& lock, const std::chrono::duration<Rep, Period>& rel_time)

根据以上条件变量的成员函数,修改代码如下:

#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <deque>
#include <condition_variable>
using namespace std;std::mutex mu;
std::deque<int> q;
std::condition_variable cond;
/*
线程1使用了 notify_one函数,来用作通知等待线程处理事务。
*/
void function_1(){int count = 100;while (count > 0) {std::unique_lock<std::mutex> locker(mu);q.push_back(count);locker.unlock();cond.notify_one();//如果环境中有多个等待线程,可以使用`notify_all()`同时触发std::this_thread::sleep_for(std::chrono::seconds(1));count--;}
}
/*
线程2是等待线程,且为了防止伪激活,这里等待线程同时加入了 lamda表达式来标示当
全局队列q也为空的时候线程2仍然处于等待状态。否则伪激活又会像上一套代码中的else
处理解锁消耗系统资源。
*/
void function_2() {int data = 0;while (data != 1) {std::unique_lock<std::mutex> locker(mu);cond.wait(locker,[](){return !q.empty();});data=q.back();q.pop_back();locker.unlock();std::cout << "t2 got a value from t1 " << data << std::endl; }
}
int main()
{std::thread t1(function_1);std::thread t2(function_2);t1.join();t2.join();return 0;
}

输出如下

t2 got a value from t1 100
t2 got a value from t1 99
t2 got a value from t1 98
t2 got a value from t1 97
t2 got a value from t1 96
t2 got a value from t1 95
...
...

参考文章:
https://en.cppreference.com/w/cpp/thread/condition_variable
https://zh.cppreference.com/w/cpp/thread/condition_variable/

相关文章:

小晶粒zsm分子筛合成表征实验报告_Nat. Mater.:区域选择性合成亚纳米金属-分子筛材料...

本文来自微信公众号&#xff1a;X-MOLNews亚纳米尺度的负载型催化剂是近些年多相催化领域以及相关材料科学领域的热门方向。围绕着单原子催化剂、团簇催化剂的论文如井喷一般出现在各大期刊上。关于亚纳米尺度金属催化剂的制备方法、表征方法、催化性能或是相关的理论研究都在如…

【翻译】使用新的Sencha Cmd 4命令app watch

原文&#xff1a;http://www.sencha.com/blog/using-the-new-app-watch-command-in-sencha-cmd-4/作者&#xff1a;Don Griffin Don Griffin is a member of the Ext JS core team. He was an Ext JS user for 2 years before joining Sencha and has over 20 years of softwar…

《设计模式解析(第2版)》

2019独角兽企业重金招聘Python工程师标准>>> 1. 软件开过程中的视角 视角 描述 概念 “软件要负责什么&#xff1f;” 规约 “怎么使用软件&#xff1f;” 实现 ”软件怎样履行自己的责任&#xff1f;“ 可能使用的另外一组视角&#xff1a;使用视角和创建/…

Nmap帮助文档解释

目标指定&#xff08;target specifiction&#xff09; 1、用法:Nmap[扫描类型][设置]{设备列表} 注&#xff1a;[]{} -> 中的内容必须有 <> -> 中的内容可以有可以没有 2、地址类型&#xff1a;主机名、ip地址、网段 3、-iL<文件名> 通过文件输入地址 4、-i…

C++ 多线程:future 异步访问类(线程之间安全便捷的数据共享)

文章目录future前言future描述future类成员使用总结future前言 首先查看如下代码 #include <iostream> #include <thread> #include <future> #include <mutex>using namespace std;void fun1(int n,int &x) {int res 1;for (int i n; i>1;…

bldc不同载波频率_广播百科 频率调制

∧ 请关注为星标&#xff0c;在知识的海洋每天进步1%第 463期频率调制&#xff0c;简称“调频”&#xff0c;它是一种使载波的瞬时频率随调制信号的变化规律而变化的调制方法。实现这种调制方法的电路称调频器,广泛用于调频广播、电视伴音、微波通信、锁相电路和扫频仪等方面。…

基于visual Studio2013解决面试题之0403串联字符串

&#xfeff;&#xfeff;&#xfeff;题目解决代码及点评/*有 n个长为 m1的字符串&#xff0c;如果某个字符串的最后m个字符与某个字符串的前m个字符匹配&#xff0c;则两个字符串可以联接&#xff0c;问这n个字符串最多可以连成一个多长的字符串&#xff0c;如果出现循环&…

MIT开放式课程“自然语言处理”介绍

MIT开放式课程“自然语言处理”介绍 发表于 2009年01月2号 由 52nlp从订阅的Google快讯上知道这个“麻省理工学院“开放式课程网页” | 电机工程与计算机科学 | 6.881 2004秋季课程&#xff1a;自然语言处理 | 课堂讲稿”网站&#xff0c;看介绍是MIT开放课程的中文翻译计划&am…

怎么将对象里面部分的属性放到一个空的对象里面去

var obj{name:jack,age:18,sex:male}var {name,age}objvar obj2{name,age}console.log(obj2) //{name: "jack", age: 18} 这是es6的用法 还有其他的3种方法,关于对象复制的 es6 var obj {name: jack,age: 18}var data Object.assign(obj)console.log(data) //{nam…

C++多线程:thread类创建线程的多种方式

文章目录描述函数成员简介总结描述 头文件 <thread> 声明方式&#xff1a;std::thread <obj> 简介 线程在构造关联的线程对象时立即开始执行&#xff0c;从提供给作为构造函数参数的顶层函数开始。如果顶层函数抛出异常&#xff0c;则调用 std::terminate。正如我…

C C++的编译过程详解

C/C编译过程C/C编译过程主要分为4个过程1) 编译预处理2) 编译、优化阶段3) 汇编过程4) 链接程序一、编译预处理&#xff08;1&#xff09;宏定义指令&#xff0c;如#define Name TokenString&#xff0c;#undef等。 对于前一个伪指令&#xff0c;预编译所要做的是将程序中的所有…

python queue 调试_学Python不是盲目的,是有做过功课认真去了解的

有多少伙伴是因为一句‘人生苦短&#xff0c;我用Python’萌生想法学Python的&#xff01;我跟大家更新过很多Python学习教程普及过多次的Python相关知识&#xff0c;不过大家还是还得计划一下Python学习路线&#xff01;Python入门前&#xff0c;你必须得知道这些&#xff0c;…

嘿嘿 刚刚进来 记录下

大家好&#xff0c;小弟刚刚进来&#xff0c;记录一下&#xff0c;发现这个网站真是太好了&#xff01;&#xff01;转载于:https://blog.51cto.com/wikowin/1112039

Oracle数据库查看表空间是否为自增的

表空间是有数据文件组成的&#xff0c;所以看表空间是否自增即看数据文件&#xff0c;如下查自增的表空间&#xff1a; select tablespace_name,file_name,autoextensible from dba_data_files where autoextensibleYES; autoextensible: YES/NO 即表示是否自增。 转载于:https…

C++多线程:异步操作std::async和std::promise

文章目录std::async简介使用案例std::promise简介成员函数总结之前的文章中提到了C多线程中的异步操作机制 C 多线程&#xff1a;future 异步访问类&#xff08;线程之间安全便捷的数据共享)&#xff0c;接下来分享关于异步操作中 async和 promise的相关使用总结。std::async …

5如何将表格的一行数据清空_微信公众号推文中如何自定义添加表格?

微信公众号发的图文消息里经常需要有表格&#xff0c;因为表格进行数据展现更直观明了&#xff0c;所以接下来就给大家分享一下如何自定义添加表格。打开小蚂蚁编辑器&#xff0c;在编辑区点击鼠标右键&#xff0c;在出现的选项中选择【插入表格】。系统会默认添加一个5行5列的…

基于visual Studio2013解决面试题之0901奇偶站队

&#xfeff;&#xfeff;&#xfeff;题目解决代码及点评/*给定一个存放整数的数组&#xff0c;重新排列数组使得数组左边为奇数&#xff0c;右边为偶数 解决方法&#xff1a;两边同时遍历&#xff0c;如果遇到左边偶数或者右边基数&#xff0c;则交换 */#include <iostrea…

联想架构调整:智能手机业务很重要

1月5日&#xff0c;杨元庆宣布联想集团进行组织架构调整。将联想旗下业务拆分为两个新的端到端业务集团—— Lenovo 业务集团和 Think 业务集团。杨元庆在内部邮件如是说:“Lenovo业务集团(Lenovo Business Group&#xff0c;简称LBG)&#xff0c;由刘军领军&#xff0c;致力于…

activiti5/6 系列之--BpmnModel使用

BpmnModel对象&#xff0c;是activiti动态部署中很重要的一个对象&#xff0c;如果BpmnModel对象不能深入的理解&#xff0c;那可能如果自己需要开发一套流程设计器&#xff0c;使用bpmn-js使用前端或者C/S展现流程流转而不是使用工作流引擎&#xff0c;就显得力不从心。例如&a…

C++多线程:package_task异步调用任何目标执行操作

文章目录描述函数成员及使用总结我们上一篇描述关于C多线程中的异步操作相关库( async和 promise)&#xff0c;本节将分享c标准库中最后一个多线程异步操作库 package_task的学习笔记。描述 头文件 <future> 声明方式: template< class R, class ...Args > class …

ICE BOX 配置,使用----第一篇

一 理论部分 (1) 为什么要使用icebox? icebox server代替了通常的server. icebox是为了方便集中管理多个ice服务而建立的。 它通过使用icebox服务器&#xff0c;把ice服务注册进去&#xff0c;从而建立联系。 所以它除了建立传统的ice服务器&#xff0c;ice客户端&#xff0c;…

测试打桩_DNF:CEO实测旭旭宝宝红眼,打桩高达2494E,伤害超越狂人剑魂

对于红眼这个职业&#xff0c;旭旭宝宝倾注了太多的心血&#xff0c;耗资几千万打造而成。虽然&#xff0c;作为固伤职业&#xff0c;在伤害方面&#xff0c;不及剑魂和剑帝这类百分比&#xff0c;但因人数颇多&#xff0c;从而被广泛关注。而今&#xff0c;旭旭宝宝的红眼&…

122112_1452_Word1

122112_1452_Word1转载于:https://www.cnblogs.com/joshuali/archive/2013/01/11/4339303.html

C++ 多线程:时间控制

C多线程库中的各个子库都有各自的时间控制方式&#xff0c;依此来进行多线程程序运行中cpu资源的精确控制。 使用std::chrono时间库可以提供微妙、毫秒、秒及以上的时间取用,并且能够获取当前系统时间。 如下代码 #include <iostream> #include <fstream> #inclu…

array用法 numpy_NumPy总结(基础用法)

numpy可以说是Python运用于人工智能和科学计算的一个重要基础&#xff0c;近段时间恰好学习了numpy&#xff0c;pandas&#xff0c;sklearn等一些Python机器学习和科学计算库&#xff0c;因此在此总结一下常用的用法。引入numpy库的方式&#xff1a;import numpy as np1、numpy…

python 字符串 转 dict

比直接eval更好的方法>>>import ast >>>ast.literal_eval("{muffin : lolz, foo : kitty}") {muffin:lolz,foo:kitty} 用 json 遇到问题&#xff1a; >>> import json json.loads({"x": 1,"y":2}) {uy: 2, ux: 1…

rhino-java中调用javascript

2019独角兽企业重金招聘Python工程师标准>>> 在有些情况下需要在java里面执行javascript&#xff0c;这时rhino就可以帮忙了。mozilla的一个开源产品。 官网https://developer.mozilla.org/en-US/docs/Rhino 之前的一篇博客http://my.oschina.net/yybear/blog/101…

HDU 2566 统计硬币

统计硬币 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 9633 Accepted Submission(s): 6505 Problem Description 假设一堆由1分、2分、5分组成的n个硬币总面值为m分&#xff0c;求一共有多少种可能的组合方式&…

linux C 多线程编程

文章目录多线程的一些小知识&#xff1a;1创建线程 pthread_create2线程挂起 pthread_join3线程终止 pthread_exit4线程分离 pthread_detach5线程取消 pthread_cancel线程同步 pthread_mutex_t互斥变量我们在写linux的服务的时候&#xff0c;经常会用到linux的多线程技术以提高…

JavaSE replaceAll 方法

private String srcStr "index\\.php\\?action";//要替换的原字符串 private String destStr "index.php?<{\\$LANGUAGE_TYPE}>action";//目的字符串 注意.和?都要转义&#xff0c;因此需要在前面添加两个反斜杠。 关于第二个参数&#xff0c;$…