使用pthreads考虑这个基本的多线程程序。 我们有一个主线程,创建另一个做一些工作的线程。
bool done = false;
mutex m;
condition c;
void foo() {
pthread_mutex_lock(&m);
//while(!done) {
pthread_cond_wait(&c, &m);
// Spuriously wakeup while child is doing work.
// child thread has NOT unlocked the mutex yet
// Do I now own the mutex?
// or am I waiting for child to unlock it?
//}
pthread_mutex_unlock(&m);
}
void * child(void *arg) {
pthread_mutex_lock(&m);
some_intense_work(); // this work is done while mutex is held!
// the main thread spuriously wakes up
// while this work is being done
// (while this child thread is holding the mutex)
done = true;
pthread_cond_broadcast(&c);
pthread_mutex_unlock(&m);
}
int main(int argc, char *argv[]) {
pthread_t p;
pthread_create(&p, NULL, child, NULL);
foo();
}
假设我们在没有周围的while子句检查谓词的情况下实现等待,即使我们知道没有人应该这样做。
现在,如果在子线程正在执行其工作时,主线程中发生虚假唤醒,互斥锁的状态将是什么?主线程是否会在没有孩子首先解锁它的情况下拥有它,所以它们都拥有它?
或者,虚假的唤醒只是跳过等待条件,而不是等待释放互斥锁?
答案 0 :(得分:2)
pthread_cond_wait()
调用不能“虚假地”唤醒,而其他一些线程持有关联的互斥锁。当pthread_cond_wait()
成功返回时,它将声明互斥锁,因此在互斥锁可用之前无法成功返回。
在您的示例中,可能会发生虚假唤醒,因为foo()
可以调用pthread_cond_wait()
并且在child()
有机会调用pthread_mutex_lock()
之前发生虚假唤醒第一名。
您示例中的另一个问题(已停用已注释的代码)是pthread_cond_wait()
调用从不唤醒的可能性。如果child()
在foo()
设法获取互斥锁之前完成所有处理,则会发生这种情况。在那种情况下,child()
将在主线程在pthread_cond_broadcast()
中等待之前调用pthread_cond_wait()
,因此主线程将错过广播。由于foo()
永远不会在持有互斥锁时检查done
,因此它不会注意到child()
已完成其工作。
这就是为什么pthread_cond_wait()
几乎总是必须在检查条件的循环中执行。