目录

前言

本文主要介绍了多线程中的条件变量,条件变量在多线程同步中用的也比较多。我第一次接触到条件变量的时候是在完成一个多线程队列的时候。条件变量用在队列没有数据时,等待入队线程入队数据。相比较于锁的使用,条件变量的使用更为复杂,使用时需要注意的部分也更多。本文将会完成一个阻塞队列(对普通队列进行一个简单的包装),以此来完成条件变量的介绍。

条件变量

条件变量(std::condition_variable)的使用需要锁的帮助。所以在定义阻塞队列时,私有成员包含了一个锁。

template<typename T>
class BlockingQueue {
public:
int pop(T &&data);
int push(T &&data);
private:
std::queue<T> m_queue;
std::condition_variable cond;
std::mutex mutex;
};

可以看到,阻塞队列的实现只有poppush两个部分,由于没有容量限制,所以只有单向的条件变量。首先是pop的实现,

int pop(T &data) {
std::unique_lock<std::mutex> lock(mutex);
if (m_queue.empty()) {
return -1;
} else {
data = m_queue.front();
m_queue.pop();
return 0;
}
}

如果不使用条件变量,很容易实现一个非阻塞的pop方法,如果队列中有数据,则返回数据,并返回0。如果没有,直接返回-1。但是如果我们想要实现在队列中没有数据的时候,程序不是直接返回而是等待直到有数据,那么最简单的方法就是借助条件变量std::condition_variable(其实只用锁也能实现,但是比较麻烦)。

int pop(T &data) {
std::unique_lock<std::mutex> lock(mutex);
while (m_queue.empty()) {
cond.wait(lock);
}
data = m_queue.front();
m_queue.pop();
return 0;
}

需要注意的是,while(m_queue.empty)这一部分,在cppreference.com中也有明确的说明,条件变量可能存在虚假的唤醒,所以需要检查是否满足条件。当然,C++也提供了wait的一个重载函数来实现对唤醒条件的检查。同时它也有超时的版本wait_forwait_until

int pop(T &data) {
std::unique_lock<std::mutex> lock(mutex); cond.wait(lock, [&]() {return m_queue.empty();}); data = m_queue.front();
m_queue.pop();
return 0;
}

然后是对push的实现,

int push(T &data) {
std::unique_lock<std::mutex> lock(mutex);
m_queue.push(data);
cond.notify_one();
return 0;
}

这里使用的是notify_one,也有notify_all但是没有必要在这使用。然后进行合并测试,可以得到以下的结果

除了std::condition_variable以外,还有一个std::condition_variable_any,它可以支持任意的锁,在使用上变化不大。

一些需要注意的地方

  1. 在唤醒线程之后,会进行加锁的操作。所以如果逻辑允许,记得手动释放锁;
  2. 注意虚假唤醒的情况;
  3. 如果记得退出线程。

总结

本文通过一个简单的例子简单介绍了一下条件变量的使用。下一篇将会介绍信号量和latch barrier,这两个都是C++20新出现的特性。

博客原文:https://www.cnblogs.com/ink19/p/std_thread-4.html

最新文章

  1. Java 标识符、数据类型、运算符
  2. Xamarin For Android 遇到错误java.exe exited with code 1. (msb6006)
  3. 【BZOJ3439】Kpm的MC密码 trie树+主席树
  4. NETBEANS + XDEBUG + IIS PHP 代码 调试 DEBUG
  5. JVM运行时内存结构
  6. linux共享文件夹
  7. 【CF17E】Palisection(回文树)
  8. 小程序实践(十):textarea实现简单的编辑文本界面
  9. virtualbmc 使用
  10. xmltodict 模块
  11. Android 9.png图片的制作方法
  12. 026_lsof命令经验总结
  13. windows系统nexus3安装和配置
  14. 指导手册03:Hadoop基础操作
  15. 20165327 2017-2018-2 《Java程序设计》第一周学习总结
  16. 看见- 柴静-kindle书摘
  17. socketio server推送
  18. Sqli-LABS通关笔录-8[延时注入]
  19. 健身VS不健身,完全是两种不同的人生!
  20. linux系统如何安装vmware Tools(下面以CentOS为例)

热门文章

  1. 写给小白看的Mysql事务
  2. 4.k8s存储之Volume、PV、PVC和StatefulSet
  3. Vue 组件内滚动条 滚到到底部
  4. 【剑指 Offer】11.旋转数组的最小数字
  5. shell 脚本安装Tomcat和java
  6. P2986 [USACO10MAR]伟大的奶牛聚集(思维,dp)
  7. centos7安装vsftpd最大的坑
  8. spring boot项目问题汇总
  9. 2021年【线上】第一性原理vasp技术实战培训班
  10. Redis 实战 —— 07. 复制、处理故障、事务及性能优化