std::condition_variable
来源:互联网 发布:customrules.js 编辑:程序博客网 时间:2024/06/06 00:27
比较常见的一个使用 std::condition_variable 场合就是线程池的消息队列。逻辑线程(可能多个)将消息推入消息队列,线程池中的工作线程(多个)会从消息队列中取出消息进行处理,如果队列中没有消息则进入睡眠状态等待消息。
本文将通过这种消息队列的实现,来分析如何使用 std::condition_variable 以及使用过程中的注意事项。
先看下这个消息队列的最终实现:
void Push(void *msg){ std::unique_lock<std::mutex> lock(m_mutex); m_queue.push(msg); lock.unlock(); m_cond.notify_one(); return;}void * WaitAndPop(){ void *msg = nullptr; while (true) { std::unique_lock<std::mutex> lock(m_mutex); if (!m_queue.empty()) { msg = m_queue.front(); m_queue.pop(); return msg; } while(m_queue.empty()) m_cond.wait(lock); } // return nullptr;}
为什么需要搭配一个互斥量使用?
先假设不需要搭配互斥量使用,代码如下
// WaitAndPopmutex.lock();if (!queue.empty){ // pop msg ...}mutex.unlock();// 标注cond.wait();
queue 会被不同线程使用,所以需要一个锁来同步。
这个锁必须在 cond.wait 前解锁,否则工作线程进入睡眠状态导致逻辑线程的 Push 无法获得锁。
那么问题来了,当 WaitAndPop 执行到 mutex.unlock 后 cond.wait 前时,逻辑线程执行了 Push ,意味着 cond.notify_one 在 cond.wait 前执行了。结果就是 工作线程进入睡眠,但是消息队列中还有一个消息没被处理 。如果后续没有新消息,那这个消息就只能永远呆在队列中了。
std::condition_variable::wait 需要一个锁作参数基本上避免了这种情况,但是不排除有的同学将这个锁和用来同步queue操作的锁分开来而导致这种情况。
Push 中调用 lock.unlock 和 cond.notify_one 的顺序问题
这是个性能优化的问题,谁先谁后对结果并没有影响。
unlock 在前,notify_one 在后。
工作线程在被唤醒前,逻辑线程已经解锁,这使得工作线程在唤醒后就能直接获得锁进入处理流程。notify_one 在前,unlock 在后。
工作线程在被唤醒后,逻辑线程可能还没有解锁,这将导致工作线程无法获得锁而又进入睡眠状态等待锁。这里多了一次上下文切换,会损失一定性能。
虚假唤醒
虚假唤醒的意思是即使没有调用 cond.notify_one , cond.wait 也有可能返回。
留意下面这段代码:
// WaitAndPopstd::unique_lock<std::mutex> lock(m_mutex);if (!m_queue.empty()) // 位置1{ ...}while(m_queue.empty()) m_cond.wait(lock); // 位置2
位置1 就是对虚假唤醒的判断处理,这一步一定要做,而且还要在获得锁后做。
位置2 是对虚假唤醒的优化,避免虚假唤醒后去争夺锁。
- std::condition_variable
- std::condition_variable 详解
- C++11 std::condition_variable
- C++11多线程(八):std::condition_variable 详解
- C++11 并发指南std::condition_variable详解
- C++11中std::condition_variable的使用
- C++11 并发指南五(std::condition_variable 详解)
- c++11 条件变量 std::condition_variable,多线程同步
- C++11 并发指南五(std::condition_variable 详解)
- C++11 并发指南五(std::condition_variable 详解)
- C++11 并发指南五(std::condition_variable 详解)
- std::thread库的condition_variable进行线程唤醒
- 关于std::condition_variable需要注意的地方spurious wake-ups
- C++11 并发指南五(std::condition_variable 详解)
- 如何用通过C++11提供的std::condition_variable实现主线程控制子线程的启动和停止
- condition_variable 锁
- boost::condition_variable的使用
- condition_variable与多线程,互斥锁
- ubuntu或linux下找不到apache服务器配置文件httpd.conf
- 万能头文件 #include<bits/stdc++.h>
- QSS美化之QPushButton
- Spring Boot 与 Spark的整合
- ant介绍
- std::condition_variable
- Java设计模式-观察者模式
- LeetCode@DFS_257_Binary_Tree_Paths
- css3text-transform,用来控制文本的大小写属性
- python2.7 32位 和 PyDev 4.2.0 32位
- Intent
- Python学习之旅-19
- 集合和数组之间的转化
- 解决win系统点击右键时鼠标一直不停转圈操作