关于pthread_cond_wait的原子性操作的问题

时间:2018-03-18 08:28:05

标签: linux multithreading race-condition

众所周知,pthread_cond_wait的调用者将通过锁定到该函数的互斥锁,然后将调用线程原子地放在等待该条件的线程列表上并解锁互斥锁。

我想知道为什么这两个步骤:

  • 将调用线程放在等待条件的线程列表上。
  • 解锁互斥锁

必须是原子的?

如果它们不是原子的,会发生什么?有两种情况:

  • 致电第1步
  • 致电第2步

  • 致电第2步
  • 致电第1步

1 个答案:

答案 0 :(得分:0)

等待(或睡眠)和释放互斥锁必须是原子的,以防止睡眠/唤醒比赛。这些是竞争条件,其中一个线程将在另一个线程正在做某事的时候进入休眠状态,这样线程不应该进入休眠状态。如果没有某种机制来阻止这种类型的竞争,尽管有工作要做,线程仍然可以处于休眠状态。 (参见例如https://www2.cs.duke.edu/courses/spring00/cps110/slides/sleepcv.pdf。)

具体而言,原子性保证在释放互斥锁之后发生的pthread_cond_signalpthread_cond_broadcast保证应用等待线程 - 即除非信号唤醒不同的等待线程,否则它将被唤醒

重要的是要理解条件变量除了等待它们的线程列表之外是无状态的。如果在没有线程等待的情况下发出条件变量信号,则该信号不执行任何操作。因此,如果首先释放互斥锁,则另一个线程可以获取互斥锁,然后在等待线程被添加到队列之前调用pthread_cond_signal并且将丢失信号。在排队是阻塞操作之后,互斥锁无法释放。 (即,线程在睡眠时无法解锁互斥锁,而睡眠调用是释放互斥锁的东西必须是原子的。)

有许多方法可以在内部实现这一点。一种是使用一些条件睡眠机制,如事件计数器。