条件变量是thread库提供的一种用于等待的同步机制,可以实现线程间的通信,它必须与互斥量配合使用,等待另一个线程中某个事件的发生(满足某个条件),然后线程才能继续执行。
thread库提供两种条件变量对象condition_variable和condition_variable_any,一般情况下,我们应该使用condition_variable_any,它能够适用更广泛的互斥量类型。
用法:拥有条件变量的线程先锁定互斥量,然后循环检查某个条件,如果条件不满足,那么就调用条件变量的成员函数wait()等待直至条件满足。其他线程处理条件变量要求的条件,当条件满足时调用它的成员函数notify_one()或notify_all(),以通知一个或者所有正在等待条件变量的线程停止等待继续执行。
wait():当前线程调用wait()后将被阻塞,直到另外某个线程调用notify_*唤醒当前线程;当线程被阻塞时,该函数会自动调用std::mutex的unlock()释放锁,使得其它被阻塞在锁竞争上的线程得以继续执行。一旦当前线程获得通知(notify,通常是另外某个线程调用notify_*唤醒了当前线程),wait()函数也是自动调用std::mutex的lock()。
生产者-消费者模式:
#include <boost/thread.hpp> #include <boost/ref.hpp> #include <iostream> #include <stack> boost::mutex io_mu; class buffer { private: boost::mutex mu; // 互斥量,配合条件变量使用 boost::condition_variable_any cond_put; // 写条件变量 boost::condition_variable_any cond_get; // 读条件变量 std::stack<int> stk; // 缓冲区对象 int un_read, capaccity; bool is_full() // 缓冲区满判断 { return un_read == capaccity; } bool is_empty() // 缓冲区空判断 { return stk.size() == 0; } public: buffer(std::size_t n) :un_read(0), capaccity(n){} void put(int x) // 写数据 { { // 开始一个局部域 boost::mutex::scoped_lock lock(mu); // 锁定互斥量 while (is_full()) // 检查缓冲区是否满 { { // 局部域,锁定io_mu boost::mutex::scoped_lock lock(io_mu); std::cout << "full waiting..." << std::endl; } cond_put.wait(mu); // 条件变量等待 } // 条件满足,停止等待 stk.push(x); // 压栈,写入数据 ++un_read; } // 通知前解锁互斥量,条件变量的通知不需要互斥量锁定 cond_get.notify_one(); // 通知可以读数据 } void get(int *x) // 读数据 { { // 局部域开始 boost::mutex::scoped_lock lock(mu); // 锁定互斥量 while (is_empty()) // 检查缓冲区是否空 { { // 锁定io_mu boost::mutex::scoped_lock lock(io_mu); std::cout << "empty waiting..." << std::endl; } cond_get.wait(mu); // 条件变量等待 } // 条件满足,停止等待 --un_read; *x = stk.top(); // 读取数据 stk.pop(); } // 通知前解锁 cond_put.notify_one(); } }; buffer buf(5); // 定义一个缓冲区对象 void producer(int n) // 生产者 { for (int i = 0; i < n; ++i) { { boost::mutex::scoped_lock lock(io_mu); std::cout << "put: " << i << std::endl; } buf.put(i); // 写入数据 } } void consumer(int n) // 消费者 { int x; for (int i = 0; i < n; ++i) { { buf.get(&x); // 读取数据 boost::mutex::scoped_lock lock(io_mu); std::cout << "get: " << x << std::endl; } } } int main() { boost::thread t1(producer, 20); boost::thread t2(consumer, 10); boost::thread t3(consumer, 10); t1.join(); t2.join(); t3.join(); return 0; }
运行截图: