标准 C++ 库提供了两个条件变量的实现:std::condition_variable 和 std::condition_variable_any。这两个实现都在头文件 <condition_variable>中声明,两者都需要和互斥锁一起使用。不同的是前者仅限于和 std::mutex 一起使用,而后者则可以与符合成为类似互斥锁的最低标准的任何东西一起使用,因此为_any 为后缀。因为 std::condition_variable 更加普遍,所以会有大小、性能或者操作系统 资源 方面的的形式的额外代价的可能 ,因此首先 std::condition_variable,除非需要额外的灵活性。
以下是一个使用条件变量 std::condition_variable 的实例:
#include <stdlib.h>
#include <stdio.h>
#include <queue>
#include <mutex>
#include <memory>
#include <thread>
#include <chrono>
#include <condition_variable>
template <typename T>
class CThreadSafe_Queue
{
public:
CThreadSafe_Queue()
{
}
CThreadSafe_Queue(CThreadSafe_Queue &other)
{
std::lock_guard<std::mutex> lock(other.mMutex);
mDataQueue = other.mDataQueue;
}
void push(T new_value)
{
std::lock_guard<std::mutex> lock(mMutex);
mDataQueue.push(new_value);
mCond.notify_one();
}
void wait_and_pop(T &value)
{
std::unique_lock<std::mutex> lock(mMutex);
mCond.wait(lock, [this]{return !mDataQueue.empty();});
value = mDataQueue.front();
mDataQueue.pop();
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lock(mMutex);
mCond.wait(lock, [this]{return !mDataQueue.empty();});
std::shared_ptr<T> ptr(std::make_shared<T>(mDataQueue.front()));
mDataQueue.pop();
return ptr;
}
bool try_pop(T &value)
{
std::lock_guard<std::mutex> lock(mMutex);
if(mDataQueue.empty())
{
return false;
}
value = mDataQueue.front();
mDataQueue.pop();
return true;
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lock(mMutex);
if(mDataQueue.empty())
{
return std::shared_ptr<T> ();
}
std::shared_ptr<T> ptr(std::make_shared<T>(mDataQueue.front()));
return ptr;
}
bool empty() const
{
std::lock_guard<std::mutex> lock(mMutex);
return mDataQueue.empty();
}
private:
mutable std::mutex mMutex;
std::queue<T> mDataQueue;
std::condition_variable mCond;
};
static CThreadSafe_Queue<int> sThreadSafeQueue;
void producer()
{
std::this_thread::sleep_for(std::chrono::seconds(3));
printf("produce !\n");
sThreadSafeQueue.push(200);
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void consume()
{
printf("consume wait!\n");
int value = 0;
sThreadSafeQueue.wait_and_pop(value);
printf("get vlaue = %d\n", value);
}
int main()
{
//首先起一个消费线程,等待数据
std::thread consumeThread(consume);
std::this_thread::sleep_for(std::chrono::seconds(1));
//其次起一个生产线程,产生数据
std::thread producerThread(producer);
consumeThread.join();
producerThread.join();
return 0;
}
main 函数里简单地实现了 2 个线程,一个生产,一个消费,消费线程首先启动,然后会进行 wait,当生产线程 push 一个数据时,条件变量调用 notify_one 进行通知,这样会唤醒执行 wait 的线程。