std::thread线程库详解(4)
目录
前言
本文主要介绍了多线程中的条件变量,条件变量在多线程同步中用的也比较多。我第一次接触到条件变量的时候是在完成一个多线程队列的时候。条件变量用在队列没有数据时,等待入队线程入队数据。相比较于锁的使用,条件变量的使用更为复杂,使用时需要注意的部分也更多。本文将会完成一个阻塞队列(对普通队列进行一个简单的包装),以此来完成条件变量的介绍。
条件变量
条件变量(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;
};
可以看到,阻塞队列的实现只有pop
和push
两个部分,由于没有容量限制,所以只有单向的条件变量。首先是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_for
和wait_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
,它可以支持任意的锁,在使用上变化不大。
一些需要注意的地方
- 在唤醒线程之后,会进行加锁的操作。所以如果逻辑允许,记得手动释放锁;
- 注意虚假唤醒的情况;
- 如果记得退出线程。
总结
本文通过一个简单的例子简单介绍了一下条件变量的使用。下一篇将会介绍信号量和latch barrier,这两个都是C++20新出现的特性。
博客原文:https://www.cnblogs.com/ink19/p/std_thread-4.html
std::thread线程库详解(4)的更多相关文章
- std::thread线程库详解(2)
目录 目录 简介 最基本的锁 std::mutex 使用 方法和属性 递归锁 std::recursive_mutex 共享锁 std::shared_mutex (C++17) 带超时的锁 总结 简 ...
- std::thread线程库详解(3)
目录 目录 前言 lock_guard scoped_lock (C++17) unique_lock shared_lock 总结 ref 前言 前两篇的博文分别介绍了标准库里面的线程和锁,这一次的 ...
- std::thread线程库详解(5)
目录 目录 前言 信号量 counting_semaphore latch与barrier latch barrier 总结 前言 前面四部分内容已经把目前常用的C++标准库中线程库的一些同步库介绍完 ...
- Java Thread(线程)案例详解sleep和wait的区别
上次对Java Thread有了总体的概述与总结,当然大多都是理论上的,这次我将详解Thread中两个常用且容易疑惑的方法.并通过实例代码进行解疑... F区别 sleep()方法 sleep()使当 ...
- Thread线程相关方法详解
1.sleep() 使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁.也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据.注意该方 ...
- “全栈2019”Java多线程第十章:Thread.State线程状态详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Lua的协程和协程库详解
我们首先介绍一下什么是协程.然后详细介绍一下coroutine库,然后介绍一下协程的简单用法,最后介绍一下协程的复杂用法. 一.协程是什么? (1)线程 首先复习一下多线程.我们都知道线程——Thre ...
- Python--urllib3库详解1
Python--urllib3库详解1 Urllib3是一个功能强大,条理清晰,用于HTTP客户端的Python库,许多Python的原生系统已经开始使用urllib3.Urllib3提供了很多pyt ...
- MySQL5.6的4个自带库详解
MySQL5.6的4个自带库详解 1.information_schema详细介绍: information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式.什么是元数据呢?元数 ...
随机推荐
- JDK1.7-HashMap原理
JDK1.7 HashMap 如何在源码上添加自己的注释 打开jdk下载位置 解压src文件夹,打开idea,ctrl+shift+alt+s打开项目配置 选择jdk版本1.7,然后点击Sourcep ...
- 【MyBatis】自定义 MyBatis
自定义 MyBatis 文章源码 执行查询信息的分析 我们知道,MyBatis 在使用代理 DAO 的方式实现增删改查时只做两件事: 创建代理对象 在代理对象中调用 selectList() 配置信息 ...
- 用js实现打印九九乘法表
用js在打印九九乘法表 思考 在学习了流程控制和条件判断后,我们可以利用js打印各式各样的九九乘法表 不管是打印什么样三角形九九乘法表,我们都应该找到有规律的地方,比如第一列的数字是什么规律,第一行的 ...
- 八:架构,搭建,WAF
WAF防护分析 什么是WAF应用 如何快速识别WAF 识别WAF对于安全测试的意义 CMS识别技术 源码获取技术 架构信息获取 站点搭建分析 搭建习惯-目录型站点 sti.blcu-bbs 目录型站点 ...
- 【EXP】根据字段导出数据query
exp有些时候需要根据字段来进行导出操作 例如:想要导出hr用户中的employees中salary要大于4000的数据 这样的话需要添加where语句,需要用到的参数是query 查看下大于4000 ...
- 【Oracle】DRM官方介绍
DRM 简介 By: Allen Gao 首先,我们对和DRM 相关的一些概念进行介绍. Buffer: 对于RAC 数据库,当一个数据块被读入到buffer cache后,我们就称其为buffer ...
- 基于kubernetes实现coredns的及验证
CoreDNS: k8s内部的DNS ,用于对pod对service做记录的,好让其他的pod做访问 这里不用做过多的阐述 官方kube-dns现在已经没有在维护了,从Kubernetes 1.11 ...
- python-列表包字典-根据字典的某一个键的值来进行排序
python-列表包字典-根据字典的某一个键的值来进行排序 列表包字典的数据结构 要实现按照字典中的某一个键所对应的值进行排序 有两种办法 方法一,使用列表的sort方法 由小到大排 列表.sort( ...
- JMeter联机负载及问题解决
主控制机:存放JMeter脚本的机器叫做主控制机 负载机:被连接并用来运行脚本的机器叫做负载机 操作步骤: 1.修改主控制机上,JMeter安装目录bin目录下的JMeter.properties文件 ...
- Failed to start ssh.service: Unit not found.
Failed to start ssh.service: Unit not found. 报错内容: [Centos7@localhost ~]$ service ssh start Redirect ...