我正在学习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);
答案 0 :(得分:46)
你应该将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>
这里的问题是线程必须在等待之前释放互斥锁,否则可能允许另一个线程“窃取”该线程正在等待的任何内容。除非保证只有一个线程可以在该条件下等待,否则在线程唤醒时假设条件有效是不正确的。
答案 1 :(得分:16)
假设您没有检查条件。然后通常你无法避免发生以下不好的事情(至少,你不能在一行代码中避免它):
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涵盖了第二个“如果”不成立的原因。