要等待的是共享状态

例如消费者发现队列为空时,真正等待的是“队列非空”这个条件,而不是某一次函数调用。消费者在持锁状态检查队列,不满足便调用等待;生产者在同一同步协议下加入数据,再通知可能等待的消费者。

C++条件变量的wait把释放相关互斥锁与进入等待作为一个原子步骤,避免检查完成后、真正等待前遗漏一次状态变化。等待返回前还要重新取得锁,因此等待期间其他线程才能进入并改变共享状态。

参考:[1] [2]

被唤醒不等于已经取得条件

C++和Rust的条件变量允许虚假唤醒;即使通知确实来自生产者,另一个消费者也可能先取得数据。因此典型写法是在循环中检查谓词,或采用接受谓词的等待接口,而不是把wait返回直接当作可以继续的证明。

notify_one在有等待者时唤醒其中一个,notify_all面向全部等待者;它们不替线程保留队列元素,也不把没有接收者的通知累计成未来许可。需要保留的事实应记录在受保护状态里,资源计数则可考虑信号量等不同抽象。

参考:[1] [2]

超时仍需回到状态与期限

超时等待提供退出等待的另一条路径,却不证明业务条件从未成立,也不保证线程恰在某个精确时刻运行。调用者需要在返回并重新持锁后,根据谓词和接口返回结果判断接下来怎么处理。

若循环每次都重新等待完整相对时长,虚假唤醒或其他唤醒可能使总等待时间延长。Rust文档特别区分这种情况,并提供带谓词的超时等待;采用统一截止时间或合适的组合接口,才能让重试与整体时间预算一致。

参考:[1] [2]