50

我正在学习 pthread 和等待条件。据我所知,典型的等待线程是这样的:

pthread_mutex_lock(&m);
while(!condition)
     pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);

我无法理解的是为什么while(!condition)即使我pthread_cond_signal()用来唤醒线程也需要这条线。

我可以理解,如果我使用pthread_cond_broadcast()我需要测试条件,因为我唤醒了所有等待的线程,其中一个线程可以在解锁互斥锁之前再次使条件为假(从而将执行转移到另一个不应该执行的唤醒线程)观点)。但是如果我使用pthread_cond_signal()我只唤醒一个线程,所以条件必须为真。所以代码可能如下所示:

pthread_mutex_lock(&m);
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);

我读了一些关于可能发生的虚假信号的文章。这是(而且只有这个)原因吗?为什么我应该有虚假信号?或者还有什么我不明白的?

我假设信号代码是这样的:

pthread_mutex_lock(&m);
condition = true;
pthread_cond_signal(&cond); // Should wake up *one* thread
pthread_mutex_unlock(&m);
4

2 回答 2

47

您应该将 pthread_cond_wait 放在 while 循环中的真正原因不是因为虚假唤醒。即使您的条件变量没有虚假唤醒,您仍然需要循环来捕获常见类型的错误。为什么?考虑如果多个线程在相同条件下等待会发生什么:

Thread 1                         Thread 2           Thread 3
check condition (fails)
(in cond_wait) unlock mutex
(in cond_wait) wait
                                 lock mutex
                                 set condition
                                 signal condvar
                                 unlock mutex
                                                    lock mutex
                                                    check condition (succeeds)
                                                    do stuff
                                                    unset condition
                                                    unlock mutex
(in cond_wait) wake up
(in cond_wait) lock mutex
<thread is awake, but condition
is unset>

这里的问题是线程必须在等待之前释放互斥锁,这可能会允许另一个线程“窃取”该线程正在等待的任何内容。除非保证只有一个线程可以在该条件下等待,否则在线程唤醒时假设该条件有效是不正确的。

于 2011-01-27T20:47:37.603 回答
17

假设您不检查条件。那么通常你无法避免以下坏事的发生(至少,你不能在一行代码中避免它):

 Sender                             Receiver
locks mutex
sets condition
signals condvar, but nothing 
  is waiting so has no effect
releases mutex
                                    locks mutex
                                    waits. Forever.

当然,您的第二个代码示例可以通过执行以下操作来避免这种情况:

pthread_mutex_lock(&m);
if (!condition) pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);

那么肯定会出现这样的情况,如果最多只有一个接收器,并且如果cond_signal是唯一可以唤醒它的东西,那么它只会在条件设置时唤醒,因此不需要循环。nos 涵盖了为什么第二个“如果”不正确。

于 2009-07-16T10:27:30.273 回答