条件变量
一般过程
等待条件变量(生产者/消费者示例中的 queueCond)始终耦合到互斥锁(生产者/消费者示例中的 queueMutex),并且应始终耦合到正常状态变量(queue.empty( )在生产者/消费者的例子中)。如果使用正确,这可确保消费者不会错过任何新数据。
一般来说,这个过程应该是:
- 对于信令线程:
- 锁定互斥锁
- 更新任何数据和状态变量
- 发出条件变量的信号
- 解锁互斥锁
- 对于等待线程:
- 锁定互斥锁
- 在状态变量上执行
while
循环,只要数据没有准备好就循环 - 在
while
循环中,使用pthread_cond_wait()
对条件变量进行等待 - 当
while
循环退出时,我们现在确定新数据已准备就绪,并且互斥锁被锁定 - 对数据做点什么
- 解锁互斥锁并重复
使用这种方案,无论何时调度信令和等待线程,等待线程都不会丢失数据(因为,它将永远不会在有效数据就绪的情况下永远等待)。这可以通过手动尝试运行信令线程的步骤,为等待线程中的每个步骤记录互斥体的状态,条件和状态变量来实现。
pthread_cond_wait
和互斥体
为了便于上述过程,需要在锁定互斥锁的情况下调用 pthread_cond_wait()
。当调用时,pthread_cond_wait()
将在线程进入休眠状态之前解锁互斥锁,并且在返回之前,无论出于何种原因,互斥锁都将被重新锁定。这也意味着如果某个其他线程当前锁定了互斥锁,pthread_cond_wait()
将等待互斥锁被解锁,直到等待线程实际上可以获取互斥锁 - 它将与其他任何试图锁定互斥锁的线程一起攻击它同时。
虚假的唤醒
此外,似乎等待状态变量的 while
循环可以替换为简单的 if
语句。然而,需要 while
循环,因为 Posix 标准允许 pthread_cond_wait()
在等待期间进行所谓的虚假唤醒,而不实际发出信号。因此,代码需要重新检查状态变量以查看 pthread_cond_wait()
是否由于实际发出信号而返回,或者由于这些虚假唤醒之一而返回。