条件变量

一般过程

等待条件变量(生产者/消费者示例中的 queueCond)始终耦合到互斥锁(生产者/消费者示例中的 queueMutex),并且应始终耦合到正常状态变量(queue.empty( )在生产者/消费者的例子中)。如果使用正确,这可确保消费者不会错过任何新数据。

一般来说,这个过程应该是:

  • 对于信令线程:
    1. 锁定互斥锁
    2. 更新任何数据和状态变量
    3. 发出条件变量的信号
    4. 解锁互斥锁
  • 对于等待线程:
    1. 锁定互斥锁
    2. 在状态变量上执行 while 循环,只要数据没有准备好就循环
    3. while 循环中,使用 pthread_cond_wait() 对条件变量进行等待
    4. while 循环退出时,我们现在确定新数据已准备就绪,并且互斥锁被锁定
    5. 对数据做点什么
    6. 解锁互斥锁并重复

使用这种方案,无论何时调度信令和等待线程,等待线程都不会丢失数据(因为,它将永远不会在有效数据就绪的情况下永远等待)。这可以通过手动尝试运行信令线程的步骤,为等待线程中的每个步骤记录互斥体的状态,条件和状态变量来实现。

pthread_cond_wait 和互斥体

为了便于上述过程,需要在锁定互斥锁的情况下调用 pthread_cond_wait()。当调用时,pthread_cond_wait() 将在线程进入休眠状态之前解锁互斥锁,并且在返回之前,无论出于何种原因,互斥锁都将被重新锁定。这也意味着如果某个其他线程当前锁定了互斥锁,pthread_cond_wait() 将等待互斥锁被解锁,直到等待线程实际上可以获取互斥锁 - 它将与其他任何试图锁定互斥锁的线程一起攻击它同时。

虚假的唤醒

此外,似乎等待状态变量的 while 循环可以替换为简单的 if 语句。然而,需要 while 循环,因为 Posix 标准允许 pthread_cond_wait() 在等待期间进行所谓的虚假唤醒,而不实际发出信号。因此,代码需要重新检查状态变量以查看 pthread_cond_wait() 是否由于实际发出信号而返回,或者由于这些虚假唤醒之一而返回。