避免虚假唤醒造成同步错误
16.7 ID_spuriouslyWakeUp
条件不满足时条件变量也可以被唤醒,这种情况称为“虚假唤醒(spurious wakeup)”,条件变量被唤醒后应检查相关条件是否满足,否则会造成同步相关的错误。
示例:
mtx_t m; // Mutex
cnd_t cv; // Condition variable
bool cnd; // Represents the condition
void thd() { // Thread function
mtx_lock(&m); // Lock
if (!cnd) { // Non-compliant, use a while loop instead
cnd_wait(&cv, &m); // Wait
}
....
}
设例中 cv 是条件变量,cnd 代表相关条件,cnd_wait 等待条件被其他异步过程满足,条件的判断与更改应是互斥的,cnd_wait 会解锁并进入等待状态,当得到 cnd_signal 或 cnd_broadcast 的通知后会退出等待状态并再次加锁,但在条件不满足时也可能退出等待,原因主要有:
- 一个条件变量对应多个条件,与当前条件无关的条件被满足并通知了条件变量
- 在退出等待并加锁的过程中其他线程使条件不被满足
- 等待过程被信号打断
这些问题取决于程序和系统的具体实现,在循环中等待并判断条件可一并解决这些问题:
void thd() {
mtx_lock(&m);
while (!cnd) { // Compliant
cnd_wait(&cv, &m);
}
....
}