天天看点

用条件变量实现事件等待器的正确与错误做法

我在拙作《Linux 多线程服务端编程:使用 muduo C++ 网络库》第 2.2 节总结了条件变量的使用要点:

条件变量只有一种正确使用的方式,几乎不可能用错。对于 wait 端:

1. 必须与 mutex 一起使用,该布尔表达式的读写需受此 mutex 保护。

2. 在 mutex 已上锁的时候才能调用 wait()。

3. 把判断布尔条件和 wait() 放到 while 循环中。

对于 signal/broadcast 端:

1. 不一定要在 mutex 已上锁的情况下调用 signal (理论上)。

2. 在 signal 之前一般要修改布尔表达式。

3. 修改布尔表达式通常要用 mutex 保护(至少用作 full memory barrier)。

4. 注意区分 signal 与 broadcast:“broadcast 通常用于表明状态变化,signal 通常用于表示资源可用。(broadcast should generally be used to indicate state change rather than resource availability。)”

版本一:错误。某书上的原始版,有丢失事件的可能。

用条件变量实现事件等待器的正确与错误做法

版本二:错误。lock() 之后再 signal(),同样有丢失事件的可能。

用条件变量实现事件等待器的正确与错误做法

版本三:错误。引入了 bool signaled_; 条件,但没有正确处理 spurious wakeup。

版本四五六:正确。仅限 single waiter 使用。

版本七:最佳。可供 multiple waiters 使用。

总结:使用条件变量,调用 signal() 的时候无法知道是否已经有线程等待在 wait() 上。因此一般总是要先修改“条件”,使其为 true,再调用 signal();这样 wait 线程先检查“条件”,只有当条件不成立时才去 wait(),避免了丢事件的可能。换言之,通过使用“条件”,将边沿触发(edge trigger)改为电平触发(level trigger)。这里“修改条件”和“检查条件”都必须在 mutex 保护下进行,而且这个 mutex 必须用于配合 wait()。

思考题:如果用两个 mutex,一个用于保护“条件”,另一个专门用于和 cond 配合 wait(),会出现什么情况?

    本文转自 陈硕  博客园博客,原文链接:http://www.cnblogs.com/Solstice/p/3309089.html,如需转载请自行联系原作者

继续阅读