原始C++标准仅支持单线程编程。新的C++标准(称为C++11或C++0x)于2011年发布。在C++11中,引入了新的线程库。因此运行本文程序需要C++至少符合C++11标准。

7 条件变量介绍

在本文中,我们将通过示例讨论C ++ 11多线程中条件变量的用法。

7.1 条件变量

条件变量是一种事件,用于在两个或多个线程之间发出信号。一个或多个线程可以等待它发出信号,而另一个线程可以发出信号。
C ++ 11中的条件变量所需的头文件是:

#include <condition_variable>

需要互斥锁以及条件变量。
条件变量如何实际起作用:

  • 线程1调用等待条件变量,该变量在内部获取互斥锁并检查是否满足所需条件。
  • 如果不是,则释放锁并等待条件变量发出信号(线程被阻塞)。条件变量的wait()函数以自动方式提供这两种操作。
  • 当满足条件时,另一个线程即线程2会发出条件变量信号。
  • 一旦收到条件变量的信号,等待它的线程1恢复。然后,它再次获取互斥锁,并检查与条件变量关联的条件是否真正满足或是否为上级调用。如果有多个线程在等待,那么notify_one将仅解除阻塞一个线程。
  • 如果是上级调用,则再次调用wait()函数。

7.2 std::condition_variable的主要成员函数

std::condition_variable的主要成员函数是:
Wait()
该函数使当前线程阻塞,直到信号通知条件变量或发生虚假唤醒为止。
它自动释放附加的互斥锁,阻塞当前线程,并将其添加到等待当前条件变量对象的线程列表中。当某些线程在同一条件变量对象上调用notify_one()或notify_all()时,该线程将被解除阻塞。它也可能会被虚假地解除阻塞,因此,每次解除阻塞后,都需要再次检查条件。
回调将作为参数传递给此函数,该函数将被调用以检查它是否是虚假调用或是否实际满足条件。wait()函数重新获取互斥锁并检查是否满足实际条件。如果不满足条件,则再次自动释放附加的互斥锁,阻塞当前线程,并将其添加到等待当前条件变量对象的线程列表中。

notify_one()
如果有任何线程在同一条件变量对象上等待,则notify_one解除阻塞其中一个等待线程。

notify_all()
如果有任何线程在相同的条件变量对象上等待,则notify_all解除所有等待线程的阻塞。

7.3 解决问题的方法

假设我们正在构建一个基于网络的应用程序。该应用程序执行以下任务,

  • 与服务器进行一些握手
  • 从XML文件加载数据。
  • 对从XML加载的数据进行处理。

如我们所见,任务1不依赖于任何其他任务,但是任务3依赖于任务2。因此,这意味着任务1和任务2可以由不同的线程并行运行以提高应用程序的性能。因此,让我们将其分解为一个多线程应用程序,

线程1的职责是

  • 与服务器进行一些连接
  • 等待线程2从XML加载数据
  • 对从XML加载的数据进行处理

线程2的职责是

  • 从XML加载数据
  • 通知另一个线程,即等待消息

使用条件变量实现此目的的代码如下:

#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application
{
std::mutex m_mutex;
std::condition_variable m_condVar;
bool m_bDataLoaded;
public:
Application()
{
m_bDataLoaded = false;
}
void loadData()
{
// Make This Thread sleep for 1 Second
// 等待1秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Loading Data from XML" << std::endl;
// Lock The Data structure
// 锁定数据结构
std::lock_guard<std::mutex> guard(m_mutex);
// Set the flag to true, means data is loaded
// 设定数据被加载
m_bDataLoaded = true;
// Notify the condition variable
// 通知变量
m_condVar.notify_one();
}
bool isDataLoaded()
{
return m_bDataLoaded;
}
void mainTask()
{
std::cout << "Do Some Handshaking" << std::endl;
// Acquire the lock
std::unique_lock<std::mutex> mlock(m_mutex);
// Start waiting for the Condition Variable to get signaled
// Wait() will internally release the lock and make the thread to block
// As soon as condition variable get signaled, resume the thread and
// again acquire the lock. Then check if condition is met or not
// If condition is met then continue else again go in wait.
// 开始等待条件变量收到信号,Wait()将在内部释放锁并使线程阻塞,一旦条件变量得到信号,就恢复线程并再次获得锁。
//然后检查是否满足条件,如果条件满足,则继续,否则继续等待。
m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this));
std::cout << "Do Processing On loaded Data" << std::endl;
}
};
int main()
{
Application app;
std::thread thread_1(&Application::mainTask, &app);
std::thread thread_2(&Application::loadData, &app);
thread_2.join();
thread_1.join();
return 0;
}

输出为:

Do Some Handshaking
Loading Data from XML
Do Processing On loaded Data

7.4 参考

https://thispointer.com//c11-multithreading-part-7-condition-variables-explained/

[编程基础] C++多线程入门7-条件变量介绍的更多相关文章

  1. [编程基础] C++多线程入门6-事件处理的需求

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 6 事件处 ...

  2. [编程基础] C++多线程入门8-从线程返回值

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 8 从线程返回值 8 ...

  3. [编程基础] C++多线程入门4-数据共享和资源竞争

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++ 11标准. 4 数据共享和资源 ...

  4. [编程基础] C++多线程入门5-使用互斥锁解决资源竞争

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 5 使用互 ...

  5. [编程基础] C++多线程入门3-小心地将参数传递给线程

    原始C++标准仅支持单线程编程.新的C++标准(称为c++11或c++0x)于2011年发布.在c++11中,引入了新的线程库.因此运行本文程序需要C++至少符合c++11标准. 文章目录 3 小心地 ...

  6. [编程基础] C++多线程入门1-创建线程的三种不同方式

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 1 创建线程的三种不 ...

  7. [编程基础] C++多线程入门10-packaged_task示例

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 10 pa ...

  8. [编程基础] C++多线程入门9-async教程和示例

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 9 asy ...

  9. [编程基础] C++多线程入门2-连接和分离线程

    原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 2 连接和 ...

随机推荐

  1. 谣言检测(ClaHi-GAT)《Rumor Detection on Twitter with Claim-Guided Hierarchical Graph Attention Networks》

    论文信息 论文标题:Rumor Detection on Twitter with Claim-Guided Hierarchical Graph Attention Networks论文作者:Erx ...

  2. 没有使用IaC的DevOps系统都是耍流氓

    作为现代软件工程的基础实践,基础设施即代码(Infrastructure as Code, IaC)是云原生.容器.微服务以及DevOps背后的底层逻辑.应该说,以上所有这些技术或者实践都是以基础设施 ...

  3. C#中ref和out关键字的应用以及区别

    首先:两者都是按地址传递的,使用后都将改变原来参数的数值. 其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所 ...

  4. Filter 筛选器(二)之 ExceptionFilter

    public class MyExceptionFilter : IAsyncExceptionFilter { private readonly ILogger<MyExceptionFilt ...

  5. IDEAidea导入Scala包

    IDEAidea导入Scala包 一.配置windows的scala的环境变量 二.IDEA导入scala插件 1.如图步骤导入IDEA的scala插件 三.添加本地的scala目录 这时候我们应该在 ...

  6. 云的安全组和网络ACL

    云的安全组和网络ACL 1.流量控制: 安全组是云服务器.数据库等实例级别的流量控制 ​ ACL是子网级别的流量控制 2.规则: 安全组和网络ACL都支持允许规则和拒绝规则 3.状态: 安全组有状态( ...

  7. Typora设置代码块Mac风格三个圆点

    写作不停,美化不止! mac小圆点效果 原本代码块样式就挺....干净的,光秃秃的,太单调了: 是吧很丑,于是自己发挥改成了这样: 好吧还是太单调,也没好看到哪里去,于是隔了两天又重新改,DuangD ...

  8. 【日志系统】Loki日志监控 - 入门初体验

    使用Grafana+Loki+Promtail入门级部署分布式日志系统(windows环境) 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放 ...

  9. ES6 学习笔记(十二)代理器Proxy的简单使用

    1.前言 以前在学习react时做了个仿手机端的QQ音乐项目.当时的数据是通过proxy代理的QQ音乐数据接口,直接写在package.json里面.Proxy 对象(Proxy)是 ES6的特性,只 ...

  10. Oracle部署,关于日志文件系统选择(硬盘格式化、挂载)

    之前部署过好多Oracle服务,采用的日志文件系统一直是ext3.但是我观察到很多人在格式化/挂载数据盘时,采用的日志文件系统类型有ext3.ext4.xfs等,这不禁让我发出疑问,哪个类型的数据处理 ...