目录

前言

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

条件变量

条件变量(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

std::thread线程库详解(4)的更多相关文章

  1. std::thread线程库详解(2)

    目录 目录 简介 最基本的锁 std::mutex 使用 方法和属性 递归锁 std::recursive_mutex 共享锁 std::shared_mutex (C++17) 带超时的锁 总结 简 ...

  2. std::thread线程库详解(3)

    目录 目录 前言 lock_guard scoped_lock (C++17) unique_lock shared_lock 总结 ref 前言 前两篇的博文分别介绍了标准库里面的线程和锁,这一次的 ...

  3. std::thread线程库详解(5)

    目录 目录 前言 信号量 counting_semaphore latch与barrier latch barrier 总结 前言 前面四部分内容已经把目前常用的C++标准库中线程库的一些同步库介绍完 ...

  4. Java Thread(线程)案例详解sleep和wait的区别

    上次对Java Thread有了总体的概述与总结,当然大多都是理论上的,这次我将详解Thread中两个常用且容易疑惑的方法.并通过实例代码进行解疑... F区别 sleep()方法 sleep()使当 ...

  5. Thread线程相关方法详解

    1.sleep() 使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁.也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据.注意该方 ...

  6. “全栈2019”Java多线程第十章:Thread.State线程状态详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. Lua的协程和协程库详解

    我们首先介绍一下什么是协程.然后详细介绍一下coroutine库,然后介绍一下协程的简单用法,最后介绍一下协程的复杂用法. 一.协程是什么? (1)线程 首先复习一下多线程.我们都知道线程——Thre ...

  8. Python--urllib3库详解1

    Python--urllib3库详解1 Urllib3是一个功能强大,条理清晰,用于HTTP客户端的Python库,许多Python的原生系统已经开始使用urllib3.Urllib3提供了很多pyt ...

  9. MySQL5.6的4个自带库详解

    MySQL5.6的4个自带库详解 1.information_schema详细介绍: information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式.什么是元数据呢?元数 ...

随机推荐

  1. servlet+jsp完成简单登录

    将用户在注册界面中的数据填充到数据库相对应的表格中.当用户再次登录时,从数据库中拿到相应的数据查询并与页面的数据做对比,判断是否登陆成功. 需要在HTML文件中将form表单上的action属性值设置 ...

  2. SpringBoot配置文件(1)

    配置文件 1.配置文件 SpringBoot使用一个全局的配置文件 application.properties application.yml 配置文件名是固定的: 他的作用是修改SpringBoo ...

  3. mac安装Navicat Premium Mac 12 破解版

    参考:https://www.cnblogs.com/lyfstorm/p/11123159.html 激活后:

  4. 系统吞吐量与QPS/TPS

    QPS/TPS QPS:Queries Per Second意思是"每秒查询率",是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准. ...

  5. 【Oracle】substr()函数详解

    Oracle的substr函数简单用法 substr(字符串,截取开始位置,截取长度) //返回截取的字 substr('Hello World',0,1) //返回结果为 'H'  *从字符串第一个 ...

  6. ctfhub技能树—信息泄露—git泄露—index

    打开靶机 查看页面信息 使用dirsearch进行扫描 使用githack工具处理git泄露情况 使用git log命令查看历史记录 与 add flag 9b5b58-- 这次提交进行比对 即可拿到 ...

  7. django使用缓存之drf-extensions

    使用方法:1.直接添加装饰器@cache_response该装饰器装饰的方法有两个要求: 它必须是继承了rest_framework.views.APIView的类的方法 它必须返回rest_fram ...

  8. 词嵌入之FastText

    什么是FastText FastText是Facebook于2016年开源的一个词向量计算和文本分类工具,它提出了子词嵌入的方法,试图在词嵌入向量中引入构词信息.一般情况下,使用fastText进行文 ...

  9. 小白的经典CNN复现(二):LeNet-5

    小白的经典CNN复现(二):LeNet-5 各位看官大人久等啦!我胡汉三又回来辣(不是 最近因为到期末考试周,再加上老板临时给安排了个任务,其实LeNet-5的复现工作早都搞定了,结果没时间写这个博客 ...

  10. 如何在 crontab 中让 source ~/.bashrc 生效

    cron 是许多类 Unix 操作系统中都自带的用来调度定时任务的工具,定时任务的配置是写在 crontab 文件中的,但是 crontab 文件不允许直接编辑,一般都是通过命令 crontab -e ...