2011-06-10 73 views
16

为什么在调用pthread_cond_wait之前需要锁定互斥锁?pthread_cond_wait和互斥要求

此外,在拨打pthread_cond_signal之前是否需要锁定(在同一个互斥体上)?

感谢您的帮助。

+2

另请参阅:http://stackoverflow.com/questions/4544234/calling-pthread-cond-signal-without-locking-mutex – ninjalj 2011-06-10 22:26:34

回答

25

为什么在调用pthread_cond_wait之前需要锁定互斥锁?

因为否则就有不可避免的竞争条件。

互斥锁保护共享状态。条件变量与状态上的某个谓词(“条件”)相关联。其基本思想是要:

1)检查谓词

2)如果断言是假的,去睡觉,直到它变成真正的

在并发系统中,总是有可能(1)和(2)之间的谓词为真。为避免这种竞争,您必须在(1)之前持有一个互斥体,并且您必须在执行(2)时自动释放它。

例如,对于一个队列,谓词可能是“队列不是空的”。但是,在检查队列是否非空以及休眠的时间之间,其他一些线程可能会将某些内容添加到队列中。

因此,您必须在检查谓词和调用pthread_cond_wait时同时持有互斥锁。

此外,在调用pthread_cond_signal之前是否需要锁定(在同一个互斥锁上)?

据我所知,这没有根本的问题;它只是引入潜在的低效率。

在这里再一次,无论您正在修改共享状态(从而使谓词为真)必须受互斥体保护。因此,无论如何,只要想要发出信号,您必须已经持有该互斥量。

如果在发送条件信号之前释放互斥锁,则由于某个其他线程的操作,谓词之间可能变为false。这场比赛不会导致失败,因为任何等待条件的线程在进行之前都必须仔细检查谓词......但为什么要通过这个麻烦呢?

底线:只要按照说明操作,您甚至不必考虑这些问题。 :-)

+0

+1了解详细的答案。 :-)我认为需要锁定信号是为了确保内存一致性,因为锁定互斥锁涉及内存屏障。没有它,其他线程可能无法观察到变化。 (虽然,我猜可能有内存屏蔽信号,但是,需要一个锁可能更简单。) – 2011-06-10 21:49:59

+1

@Chris:POSIX需要'pthread_cond _ *()'来同步内存:http:// pubs。 opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11 – ninjalj 2011-06-10 22:05:26

+0

@ninjalj:啊,非常好。谢谢! :-) – 2011-06-10 22:12:15

1

条件变量用于在您希望更改的条件下进行同步。锁定确保:

  • 的改变可以在等待的线程可以可靠地观察到
  • 下变化的项目不以某种方式通过另一个线程同时现已唤醒的线程之一改变时,观察它

不使用互斥锁的条件系统会更脆弱。

1

条件变量的要点是允许向线程通知由互斥锁保护的数据结构上的更改,例如,您可能希望在队列不再为空时通知您,因此您可以以原子方式释放互斥锁并等待条件变量,并且当新元素排队时,您将唤醒并使用互斥锁处理新元素。

与Java的监视器不同,pthread_cond_{signal,broadcast}()不需要保存互斥量。当没有线程在该条件变量上等待时,发送一个条件变量的信号会丢失,但这不应该产生很大的差别,因为如果生产者在消费者之前开始运行,信号也可能丢失。