深入理解C++并发编程中的条件变量:以CPP-Concurrency-In-Action-2ed为例
条件变量基础概念
条件变量是多线程编程中用于线程间同步的重要工具。在C++标准库中,<condition_variable>
头文件提供了两种条件变量实现:std::condition_variable
和std::condition_variable_any
。
std::condition_variable详解
基本特性
std::condition_variable
是C++标准库提供的基本条件变量实现,它必须与std::unique_lock<std::mutex>
配合使用。这种设计提供了最佳性能,但限制了锁类型的灵活性。
核心成员函数
-
等待函数
wait()
: 无条件等待,直到被通知wait(pred)
: 带谓词的等待,避免虚假唤醒wait_for()
: 带超时的等待wait_until()
: 带绝对时间点的等待
-
通知函数
notify_one()
: 唤醒一个等待线程notify_all()
: 唤醒所有等待线程
使用模式
典型的使用模式如下:
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
// 等待线程
std::unique_lock<std::mutex> lk(mtx);
cv.wait(lk, []{return ready;});
// 通知线程
{
std::lock_guard<std::mutex> lk(mtx);
ready = true;
}
cv.notify_one();
std::condition_variable_any详解
与std::condition_variable的区别
std::condition_variable_any
提供了更大的灵活性,可以与任何满足基本锁概念(Lockable)的类型一起使用,而不仅限于std::unique_lock<std::mutex>
。
适用场景
当需要使用自定义锁类型或需要更灵活的锁管理时,std::condition_variable_any
是更好的选择。不过这种灵活性通常伴随着轻微的性能开销。
关键注意事项
-
虚假唤醒:线程可能在没有收到通知的情况下被唤醒,因此总是应该在循环中检查条件。
-
通知丢失:如果在通知时没有线程在等待,通知将被丢弃。
-
锁的管理:条件变量等待时会自动释放锁,并在返回前重新获取锁。
-
线程退出通知:
std::notify_all_at_thread_exit
允许在线程退出时自动通知条件变量。
性能考虑
std::condition_variable
通常比std::condition_variable_any
性能更好- 过多的通知(
notify_all
)可能导致"惊群效应" - 合理使用带谓词的等待可以减少不必要的唤醒
最佳实践
- 优先使用带谓词的等待版本
- 考虑使用
wait_until
而不是wait_for
处理长时间等待 - 确保在修改条件变量关联的状态时持有锁
- 仔细设计通知策略,避免不必要的线程唤醒
通过深入理解这些概念和技巧,开发者可以更有效地使用C++条件变量来构建可靠且高效的并发程序。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考