由pthread_cond_signal()唤醒但失去了对互斥锁的竞争的线程会发生什么

rac*_*cic 2 c mutex pthreads condition-variable

关于这个: 如何使用条件变量

假设我们有许多执行此类代码的消费者线程(从引用的页面复制):

while (TRUE) {
    s = pthread_mutex_lock(&mtx);
    while (avail == 0) {   /* Wait for something to consume */
       s = pthread_cond_wait(&cond, &mtx);
    }
    while (avail > 0) {   /* Consume all available units */ 
        avail--;
    }
    s = pthread_mutex_unlock(&mtx);
}
Run Code Online (Sandbox Code Playgroud)

我假设这里的场景是:主线程调用pthread_cond_signal()来告诉消费者线程做一些工作.

据我所知 - 后续线程调用pthread_mutex_lock()然后调用pthread_cond_wait()(以原子方式解锁互斥锁).到目前为止,没有任何消费者线程声称使用互斥锁,它们都在pthread_cond_wait()上等待.

当主线程调用pthread_cond_signal()时,在联机帮助页之后,至少会唤醒一个线程.当它们中的任何一个从pthread_cond_wait()返回时,它会自动声明互斥锁.

所以我的问题是:现在关于提供的示例代码会发生什么?也就是说,失去互斥体竞赛的线程现在做了什么?

(AFAICT赢得互斥锁的线程,应该运行其余的代码并释放互斥锁.丢失的那个应该等待互斥锁 - 在第一个嵌套 while循环中的某个地方- 而胜利者持有它并且在它被释放之后在pthread_cond_wait()上开始阻塞,因为while (avail == 0)那时将满足.我是否正确?)

Mic*_*urr 6

注意,pthread_cond_signal()通常只是为了唤醒一个等待的线程(这就是它保证的全部).但它可能会"意外地"唤醒.所述while (avail > 0)循环执行两个功能:

  • 它允许保证一个线程被唤醒以消耗所有排队的工作单元
  • 它可以防止额外的"意外"唤醒线程假设有工作要做,而可能没有,因为初始线程将处理所有这些.

它还可以防止在while (avail > 0)完成后工作单元可能已经放入队列的竞争条件,但是在工作线程再次等待条件之前 - 但是该竞争也在if调用之前由测试处理pthread_cond_wait().

基本上当一个线程被唤醒时,它只知道可能有工作单元供它使用,但可能没有(另一个线程可能已经消耗它们).

所以pthread_cond_signal()调用时发生的事件序列是:

  • 系统将唤醒一个或多个等待该条件的线程
  • 所有被唤醒的线程将尝试获取互斥锁 - 只有其中一个可以在任何特定时刻获取它,因为这是互斥的目的
  • 然后该线程将继续,在while (avail > 0)循环中执行工作,然后将释放互斥锁
  • 此时,之前被唤醒的其他线程之一将获取互斥锁并运行相同的循环,然后释放互斥锁.通常,将不再有可用的工作单元(因为第一个线程将消耗所有工作单元),但如果另一个线程添加了一个额外的单元(或更多),那么该线程将处理该工作
  • 下一个线程将获取互斥锁并执行同一组逻辑

  • 从'pthread_cond_wait()返回之前,'丢失'线程将在互斥锁上被阻塞,因为`pthread_cond_wait()`必须在让它返回之前获取该线程的互斥锁.一旦"获胜"线程释放互斥锁,失败的线程将能够获取它并继续从`pthread_cond_wait()返回. (3认同)