原始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. DDD-领域驱动(四)-使用IMediator 实现领域事件

    领域事件是指:一个领域中出触发的 集成事件是指:多个微服务之前产生的事件 核心对象 IMediator INotification INotificationHandler 引入:IMediator ...

  2. js红宝书学习笔记(一)引用类型

    一.引用类型 ECMAScript中,引用类型是一种数据结构称之为对象定义,,引用对象不同于传统面向对象语言所支持的类和接口等基本结构 创建Object 实例的两种方式: new操作符跟Object构 ...

  3. 线性表的基本操作(C语言实现)

    文章目录 这里使用的工具是DEV C++ 可以借鉴一下 实现效果 顺序存储代码实现 链式存储存储实现 这里使用的工具是DEV C++ 可以借鉴一下 一.实训名称 线性表的基本操作 二.实训目的 1.掌 ...

  4. 0025:2011年NOIp普及组真题——瑞士轮题解

    题目链接:https://www.luogu.com.cn/problem/P1309 如果是新手可能马上会想到sort排序,每比一次就排一次,但是这样的时间复杂度有点高,只有60分: 这是因为每次比 ...

  5. 基于BP神经网络的手MNIST写数字识别

    import numpy import math import scipy.special#特殊函数模块 import matplotlib.pyplot as plt #创建神经网络类,以便于实例化 ...

  6. docker容器化业务

    1.环境准备: 设备 IP地址 作用 系统版本 mysql-master 192.168.100.213 Nginx-Web服务器 Ubuntu2004 mysql-slave 192.168.100 ...

  7. SpringCloud(六) - RabbitMQ安装,三种消息发送模式,消息发送确认,消息消费确认(自动,手动)

    1.安装erlang语言环境 1.1 创建 erlang安装目录 mkdir erlang 1.2 上传解压压缩包 上传到: /root/ 解压缩# tar -zxvf otp_src_22.0.ta ...

  8. MQTT GUI 客户端 可视化管理工具推荐

    一款好用的 MQTT 客户端工具可以极大地提高开发者使用MQTT的效率.MQTT 客户端工具常用于建立与 MQTT 服务器的连接,进行主题订阅.消息收发等操作. 今天,在此推荐一款优秀的MQTT GU ...

  9. mybatis实现数据行级权限拦截

    最近在做一个测试平台,其中有一个需求是用户只能看到他有权限的项目数据.一开始这个需求只针对用例模块,我直接在sql后面加上了关联项目权限表.后面因为其他模块也需要这个权限判断,故打算把关联sql抽取出 ...

  10. 自学 TypeScript 第一天 环境开发配置 及 TS 基本类型声明

    前言:  自学第一天,什么是TS ,为什么要用 TS TS 全程 Typed JavaScript at Any Scale 解释起来就是 添加了类型系统的 JavaScript, 是 JavaScr ...