1 condition_variable
参考:https://www.cnblogs.com/GuoXinxin/p/11675053.html
当 std::condition_variable对象的某个wait 函数被调用的时候,它使用 std::unique_lock(通过 std::mutex) 来锁住当前线程。
当前线程会一直被堵塞。直到另外一个线程在同样的 std::condition_variable 对象上调用了 notification 函数来唤醒当前线程。
1.1 condition_variable的wait()介绍
两种wait()函数:
void wait (unique_lock<mutex>& lck);
template <class Predicate>
void wait (unique_lock<mutex>& lck, Predicate pred);
当前线程调用 wait() 后将被堵塞(此时当前线程应该获得了锁(mutex),最好还是设获得锁 lck),直到另外某个线程调用 notify_* 唤醒了当前线程。
在线程被堵塞时,该函数会自己主动调用 lck.unlock() 释放锁,使得其它被堵塞在锁竞争上的线程得以继续运行。另外,一旦当前线程获得通知(notified,一般是另外某个线程调用 notify_* 唤醒了当前线程),wait()函数也是自己主动调用 lck.lock(),使得lck的状态和 wait 函数被调用时同样。
在另外一种情况下(即设置了 Predicate)。仅仅有当 pred 条件为false 时调用 wait() 才会堵塞当前线程。而且在收到其它线程的通知后仅仅有当 pred 为 true 时才会被解除堵塞。
1.2 std::condition_variable::notify_one()
唤醒某个等待(wait)线程。假设当前没有等待线程,则该函数什么也不做,假设同一时候存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。
1.3 std::condition_variable::notify_all()
唤醒全部的等待(wait)线程。假设当前没有等待线程,则该函数什么也不做。
2 示例:多线程读取写入图片
#ifndef IMAGEBUFFER_H
#define IMAGEBUFFER_H
#include <opencv2/opencv.hpp>
#include <mutex>
#include <condition_variable>
#include <queue>
template<typename T>
class ConsumerProducerQueue
{
public:
ConsumerProducerQueue(int mxsz,bool dropFrame) :
maxSize(mxsz),dropFrame(dropFrame)
{ }
void add(T request)
{
std::unique_lock<std::mutex> lock(mutex);
if(dropFrame && isFull())
{
lock.unlock();
return;
}
else {
cond.wait(lock, [this]() { return !isFull(); });
cpq.push(request);
cond.notify_all(); // 唤醒用其它用条件变量wait()阻塞了的线程
}
}
void consume(T &request)
{
std::unique_lock<std::mutex> lock(mutex);
cond.wait(lock, [this]()
{ return !isEmpty(); });
request = cpq.front();
cpq.pop();
//lock.unlock();
cond.notify_all();
}
bool isFull() const
{
return cpq.size() >= maxSize;
}
bool isEmpty() const
{
return cpq.size() == 0;
}
int length() const
{
return cpq.size();
}
void clear()
{
std::unique_lock<std::mutex> lock(mutex);
while (!isEmpty())
{
cpq.pop();
}
lock.unlock();
cond.notify_all();
}
private:
std::condition_variable cond;
std::mutex mutex;
std::queue<T> cpq;
int maxSize;
bool dropFrame;
};
#endif