std::thread线程库详解(4)
2021-02-07 15:51
66 查看
目录
前言
本文主要介绍了多线程中的条件变量,条件变量在多线程同步中用的也比较多。我第一次接触到条件变量的时候是在完成一个多线程队列的时候。条件变量用在队列没有数据时,等待入队线程入队数据。相比较于锁的使用,条件变量的使用更为复杂,使用时需要注意的部分也更多。本文将会完成一个阻塞队列(对普通队列进行一个简单的包装),以此来完成条件变量的介绍。
条件变量
条件变量(
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新出现的特性。
相关文章推荐
- std::thread详解
- C++11 并发指南二(std::thread 详解)
- 【C/C++开发】C++11 并发指南二(std::thread 详解)
- C++11 并发指南二(std::thread 详解)
- std::thread线程详解(1)
- C++11 并发指南------std::thread 详解
- C++11 并发指南之std::thread 详解
- C++11 并发指南二(std::thread 详解)
- C++11 并发指南二(std::thread 详解)
- C++11 并发指南二(std::thread 详解)
- c++11中关于std::thread的join的详解
- C++11 并发指南二(std::thread 详解)
- C++11 并发指南二(std::thread 详解)
- C++11 并发指南二(std::thread 详解)
- C++11 并发指南------std::thread 详解
- C++11 并发指南二(std::thread 详解)
- C++11 并发指南二(std::thread 详解)
- C++11 并发指南二(std::thread 详解)(转)
- C++ using namespace std 详解
- C#,JAVA各版本之Thread.join()详解