返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >c++多线程要使用条件变量的原因
  • 202
分享到

c++多线程要使用条件变量的原因

2023-06-15 09:06:06 202人浏览 独家记忆
摘要

小编给大家分享一下c++多线程要使用条件变量的原因,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!先看示例1:#include <iOStream&

小编给大家分享一下c++多线程要使用条件变量的原因,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

先看示例1:

#include <iOStream>#include <windows.h>#include <mutex>#include<deque>#include <thread>using namespace std;int nmax = 20;std::deque<int> m_que;std::mutex mymutex;//生产者void producterex(){int i = 1;while (i<nmax){//休眠一秒钟std::this_thread::sleep_for(std::chrono::seconds(1));std::unique_lock<mutex> lcx(mymutex);m_que.push_back(i);cout << "producted:" << i << endl;lcx.unlock();i++;}cout << "product thread exit\n";}//消费者void consumerex(){int i = 0;while (1){std::unique_lock<mutex> lcx(mymutex);if (!m_que.empty()){int i = m_que.back();m_que.pop_back();cout << "consumed:" << i << endl;lcx.unlock();i++;if (i == nmax){break;}}else{lcx.unlock();}}cout << "consumerex thread exit\n";}void main(){std::thread t1(producterex);std::thread t2(consumerex);t1.detach();cout << "hello";t2.detach();cout << " world!\n";getchar();system("pause");}

结果:

c++多线程要使用条件变量的原因

c++多线程要使用条件变量的原因

可见cpu使用率非常高。高的原因主要在消费者线程中,因为当队列为空的时候它也要执行,做了过多的无用功导致CPU占有率过高,所以下面对进行一个改造让其在空的时候等待200毫秒,相当于增大了轮询间隔周期,应该能降低CPU的占用率。

在这里就贴上消费者的线程,因为其它的都一样。

//消费者void consumerex(){int i = 0;while (1){std::unique_lock<mutex> lcx(mymutex);if (!m_que.empty()){int i = m_que.back();m_que.pop_back();cout << "consumed:" << i << endl;lcx.unlock();i++;if (i == nmax){break;}}else{lcx.unlock();std::this_thread::sleep_for(std::chrono::milliseconds(200));}}cout << "consumerex thread exit\n";}

结果:

c++多线程要使用条件变量的原因

可见CPU占用率一下子下降了。

这里就有一个困难了,那就是如何确定休眠的时间间隔(即轮询间隔周期),如果间隔太短会过多占用CPU资源,如果间隔太长会因无法及时响应造成延误。

这就引入了条件变量来解决该问题:条件变量使用“通知—唤醒”模型,生产者生产出一个数据后通知消费者使用,消费者在未接到通知前处于休眠状态节约CPU资源;当消费者收到通知后,赶紧从休眠状态被唤醒来处理数据,使用了事件驱动模型,在保证不误事儿的情况下尽可能减少无用功降低对资源的消耗。

condition_variable介绍
在C++11中,我们可以使用条件变量(condition_variable)实现多个线程间的同步操作;当条件不满足时,相关线程被一直阻塞,直到某种条件出现,这些线程才会被唤醒。

成员函数如下:

c++多线程要使用条件变量的原因

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:

a.一个线程因等待"条件变量的条件成立"而挂起;

b.另外一个线程使"条件成立",给出信号,从而唤醒被等待的线程。

为了防止竞争,条件变量的使用总是和一个互斥结合在一起;通常情况下这个锁是std::mutex,并且管理这个锁 只能是 std::unique_lockstd::mutex RAII模板类。

上面提到的两个步骤,分别是使用以下两个方法实现:

等待条件成立使用的是condition_variable类成员wait 、wait_for 或 wait_until。

给出信号使用的是condition_variable类成员notify_one或者notify_all函数。

以上两个类型的wait函数都在会阻塞时,自动释放锁权限,即调用unique_lock的成员函数unlock(),以便其他线程能有机会获得锁。这就是条件变量只能和unique_lock一起使用的原因,否则当前线程一直占有锁,线程被阻塞。

虚假唤醒

在正常情况下,wait类型函数返回时要不是因为被唤醒,要不是因为超时才返回,但是在==实际中发现,因此操作系统的原因,wait类型在不满足条件时,它也会返回,这就导致了虚假唤醒。==因此,我们一般都是使用带有谓词参数的wait函数,因为这种(xxx, Predicate pred )类型的函数等价于:

while (!pred()) //while循环,解决了虚假唤醒的问题{    wait(lock);}

原因说明如下:

假设系统不存在虚假唤醒的时,代码形式如下:

if (不满足xxx条件){    //没有虚假唤醒,wait函数可以一直等待,直到被唤醒或者超时,没有问题。    //但实际中却存在虚假唤醒,导致假设不成立,wait不会继续等待,跳出if语句,    //提前执行其他代码,流程异常    wait();  }//其他代码...

正确的使用方式,使用while语句解决:

while (!(xxx条件) ){    //虚假唤醒发生,由于while循环,再次检查条件是否满足,    //否则继续等待,解决虚假唤醒    wait();  }//其他代码....

下面看一个使用条件变量的情况:

#include <iostream>#include <windows.h>#include <mutex>#include<deque>#include <thread>#include<condition_variable>using namespace std;int nmax = 10;std::deque<int> m_que;std::mutex mymutex;condition_variable mycv;//生产者void producterex(){int i = 1;while (i<nmax){//休眠一秒钟std::this_thread::sleep_for(std::chrono::seconds(1));std::unique_lock<mutex> lcx(mymutex);m_que.push_back(i);cout << "producted:" << i << endl;lcx.unlock();mycv.notify_one();i++;}cout << "product thread exit\n";}//消费者bool m_bflag = false;void consumerex(){int i = 0;bool m_bexit = false;while (!m_bexit){std::unique_lock<mutex> lcx(mymutex);while (m_que.empty()){//避免虚假唤醒mycv.wait(lcx);if (m_bflag){cout << "consumerex thread exit\n";m_bexit = true;break;}}if (m_bexit){break;}int i = m_que.back();m_que.pop_back();lcx.unlock();cout << "consumed:" << i << endl;}cout << "consumerex thread exit\n";}void main(){std::thread t1(producterex);std::thread t2(consumerex);t1.detach();cout << "hello";t2.detach();cout << " world!\n";mycv.notify_one();Sleep(15000);m_que.push_back(100);mycv.notify_one();Sleep(3000);m_bflag = true;mycv.notify_one();//通知线程退出getchar();system("pause");}

结果:

c++多线程要使用条件变量的原因

还可以将mycv.wait(lcx);换一种写法,wait()的第二个参数可以传入一个函数表示检查条件,这里使用lambda函数最为简单,如果这个函数返回的是true,wait()函数不会阻塞会直接返回,如果这个函数返回的是false,wait()函数就会阻塞着等待唤醒,如果被伪唤醒,会继续判断函数返回值。代码示例如下:

#include <iostream>#include <windows.h>#include <mutex>#include<deque>#include <thread>#include<condition_variable>using namespace std;int nmax = 10;std::deque<int> m_que;std::mutex mymutex;condition_variable mycv;//生产者void producterex(){int i = 1;while (i<nmax){//休眠一秒钟std::this_thread::sleep_for(std::chrono::seconds(1));std::unique_lock<mutex> lcx(mymutex);m_que.push_back(i);cout << "producted:" << i << endl;lcx.unlock();mycv.notify_one();i++;}cout << "product thread exit\n";}//消费者bool m_bflag = false;void consumerex(){int i = 0;while (1){std::unique_lock<mutex> lcx(mymutex);mycv.wait(lcx, [](){//返回false就继续等待return !m_que.empty();});if (m_bflag){break;}int i = m_que.back();m_que.pop_back();lcx.unlock();cout << "consumed:" << i << endl;}cout << "consumerex thread exit\n";}void main(){std::thread t1(producterex);std::thread t2(consumerex);t1.detach();cout << "hello";t2.detach();cout << " world!\n";mycv.notify_one();Sleep(15000);m_que.push_back(100);mycv.notify_one();Sleep(3000);m_bflag = true;m_que.push_back(-1);mycv.notify_one();//通知线程退出getchar();system("pause");}

c++多线程要使用条件变量的原因

以上是“c++多线程要使用条件变量的原因”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网其他教程频道!

--结束END--

本文标题: c++多线程要使用条件变量的原因

本文链接: https://lsjlt.com/news/279215.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • c++多线程要使用条件变量的原因
    小编给大家分享一下c++多线程要使用条件变量的原因,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!先看示例1:#include <iostream&...
    99+
    2023-06-15
  • c++多线程为何要使用条件变量详解
    先看示例1: #include <iostream> #include <windows.h> #include <mutex> #inclu...
    99+
    2024-04-02
  • C++多线程互斥锁和条件变量的详解
    目录互斥锁:std::mutex::try_lock         条件变量:condition_variable总结我们了解互斥...
    99+
    2024-04-02
  • ReentrantLock条件变量使多个线程顺序执行
    目录一. 前言二. 解决方案三. 使用ReentrantLock 条件变量四. 后话一. 前言 近日一个学生在参加某公司校招面试时,遇到一个多个线程顺序执行的面试题,特意记录下来和大...
    99+
    2022-12-19
    ReentrantLock多个线程顺序执行 ReentrantLock条件变量
  • 详解C++11中的线程锁和条件变量
    目录线程锁条件变量小结线程 std::thread类, 位于<thread>头文件,实现了线程操作。std::thread可以和普通函数和 lambda 表达式搭配使用。...
    99+
    2024-04-02
  • C++11中线程、锁和条件变量的介绍
    这篇文章主要介绍“C++11中线程、锁和条件变量的介绍”,在日常操作中,相信很多人在C++11中线程、锁和条件变量的介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++11中线程、锁和条件变量的介绍”的疑...
    99+
    2023-06-17
  • C++11线程、互斥量及条件变量怎么创建
    这篇“C++11线程、互斥量及条件变量怎么创建”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++11线程、互斥量及条件变量...
    99+
    2023-07-05
  • C++11 condition_variable条件变量怎么使用
    今天小编给大家分享一下C++11 condition_variable条件变量怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们...
    99+
    2023-07-02
  • C++11中线程锁和条件变量的示例分析
    这篇文章主要介绍了C++11中线程锁和条件变量的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。线程std::thread类, 位于<thread>头文件,...
    99+
    2023-06-15
  • 怎么理解C++11 中的线程及锁和条件变量
    今天就跟大家聊聊有关怎么理解C++11 中的线程及锁和条件变量,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。线程类std::thread代表一个可执行线程,使用时必须包含头文件<...
    99+
    2023-06-17
  • java使用多线程的条件是什么
    使用多线程的条件有以下几个:1. 程序需要并发执行多个任务或同时处理多个请求。2. 程序中存在可分解为独立子任务的任务集合。3. 程...
    99+
    2023-09-26
    java
  • 反对使用Spring封装的多线程类原因
    目录1.Spring的异步代码2.是SpringBoot救了你3.End前言: 工作总难免会遇到被故障所驱使,其实是开启了线程池的暴力使用模式 我有必要简单的复述一下。其主要原因,就...
    99+
    2024-04-02
  • C++11 condition_variable条件变量的用法说明
    目录1 什么是条件变量2 condition_variable类定义2.1 wait函数3 condition_variable用法3.1 资源修改线程步骤3.2 资源等待线程步骤4...
    99+
    2024-04-02
  • GoLang并发编程中条件变量sync.Cond的使用
    目录一、条件变量与互斥锁二、条件变量与互斥锁的配合使用三、条件变量的使用创建锁和条件使用四、条件变量的Wait方法做了什么一、条件变量与互斥锁 条件变量是基于互斥锁的,它必须基于互斥...
    99+
    2023-01-10
    Go sync.Cond介绍 Go sync.Cond使用
  • 使用条件变量的坑有哪些
    本篇内容介绍了“使用条件变量的坑有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 什么是...
    99+
    2024-04-02
  • 线程局部变量使用与多线程开发的示例分析
    这篇文章主要为大家展示了“线程局部变量使用与多线程开发的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“线程局部变量使用与多线程开发的示例分析”这篇文章吧。一、概述现在多核时代多线程开发越...
    99+
    2023-06-17
  • Linux C中多线程与volatile变量的示例分析
    这篇文章主要介绍Linux C中多线程与volatile变量的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Linux C中多线程与volatile变量volatile 修饰的变量表示改变量的值是易变的,编译...
    99+
    2023-06-09
  • C#进度条使用之多线程应用如何实现
    这篇文章将为大家详细讲解有关C#进度条使用之多线程应用如何实现,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。让我们来看看具体的实现://声明一个委托 ,C#进度条使用之多线程应用 pu...
    99+
    2023-06-17
  • 反对使用Spring封装的多线程类原因是什么
    本文小编为大家详细介绍“反对使用Spring封装的多线程类原因是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“反对使用Spring封装的多线程类原因是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。前言:...
    99+
    2023-06-30
  • C++多线程std::call_once的使用
    在多线程的环境下,有些时候我们不需要某个函数被调用多次或者某些变量被初始化多次,它们仅仅只需要被调用一次或者初始化一次即可。很多时候我们为了初始化某些数据会写出如下代码,这些代码在单...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作