std::condition_variable
std::condition_variable,是C++11提供的条件变量,可用于同时阻塞一个线程或多个线程。一般的,生产者线程利用支持std::mutex的std::lock_guard/std::unique_lock修改共享变量后,并通知condition_variable。消费者线程获取同一个std::mutex(std::unique_lock所持有),并调用std::condition_variable的wait, wait_for, or wait_until。wait操作会释放互斥量,同时挂起该线程。当条件变量收到通知、超时到期或发生虚假唤醒时,线程被唤醒,互斥量也被原子地重新获取。需要注意的是,如果是虚假唤醒,线程应该检查条件并继续等待,以保证业务的正确性。
std::condition_variable::wait()
unconditional (1) | void wait( std::unique_lockstd::mutex& lock ); |
---|---|
predicate (2) | template< class Predicate > void wait( std::unique_lock< std::mutex >& lock, Predicate stop_waiting ); |
wait() 有两个重载,第二个算是一个语法糖,可用于在等待特定条件变为真时忽略虚假唤醒。相当于:
while (!stop_waiting()) {
wait(lock);
}
注意:lock必须在wait()前调用,可以用来守护访问stop_waiting()。wait(lock)返回后会重新获取该lock。
示例:
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Wait until main() sends data
std::unique_lock lock(mtx);
cv.wait(lock, []{return ready;});
// after the wait, we own the lock.
std::cout << "Worker thread is processing data\n";
data += " after processing";
// Send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completed\n";
// Manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_one for details)
lock.unlock();
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard lock(mtx);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock lock(mtx);
cv.wait(lock, []{return processed;});
}
std::cout << "Back in main(), data = " << data << '\n';
worker.join();
}
输出:
main() signals data ready for processing
Worker thread is processing data
Worker thread signals data processing completed
Back in main(), data = Example data after processing