虚假唤醒后的互斥锁状态
Mutex status after spurious wakeup
考虑这个使用 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 子句检查谓词的等待,即使我们知道没有人应该这样做。
现在,如果在子线程工作时,主线程发生虚假唤醒,互斥体 m 的状态会是什么?主线程是否会在子线程不先解锁的情况下拥有它,以便双方都拥有它?
或者虚假唤醒只跳过对条件的等待,而不是等待释放互斥量?
pthread_cond_wait()
调用无法 'spuriously' 在其他线程持有关联的互斥体时唤醒。当 pthread_cond_wait()
return 成功时,它将获得互斥量,因此在互斥量可用之前它无法成功 return。
在您的示例中,可能会发生虚假唤醒,因为 foo()
可以调用 pthread_cond_wait()
并在 child()
有机会调用 pthread_mutex_lock()
之前发生虚假唤醒首先。
您的示例中的另一个问题(禁用注释代码)是 pthread_cond_wait()
调用可能 never 唤醒。如果 child()
在 foo()
设法获取互斥锁之前完成所有处理,就会发生这种情况。在这种情况下,child()
将在主线程等待 pthread_cond_wait()
之前调用 pthread_cond_broadcast()
,因此主线程将错过广播。由于 foo()
在持有互斥量时从不检查 done
,因此它不会注意到 child()
已完成其工作。
这就是为什么 pthread_cond_wait()
几乎总是必须在检查条件的循环中执行。
考虑这个使用 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 子句检查谓词的等待,即使我们知道没有人应该这样做。
现在,如果在子线程工作时,主线程发生虚假唤醒,互斥体 m 的状态会是什么?主线程是否会在子线程不先解锁的情况下拥有它,以便双方都拥有它?
或者虚假唤醒只跳过对条件的等待,而不是等待释放互斥量?
pthread_cond_wait()
调用无法 'spuriously' 在其他线程持有关联的互斥体时唤醒。当 pthread_cond_wait()
return 成功时,它将获得互斥量,因此在互斥量可用之前它无法成功 return。
在您的示例中,可能会发生虚假唤醒,因为 foo()
可以调用 pthread_cond_wait()
并在 child()
有机会调用 pthread_mutex_lock()
之前发生虚假唤醒首先。
您的示例中的另一个问题(禁用注释代码)是 pthread_cond_wait()
调用可能 never 唤醒。如果 child()
在 foo()
设法获取互斥锁之前完成所有处理,就会发生这种情况。在这种情况下,child()
将在主线程等待 pthread_cond_wait()
之前调用 pthread_cond_broadcast()
,因此主线程将错过广播。由于 foo()
在持有互斥量时从不检查 done
,因此它不会注意到 child()
已完成其工作。
这就是为什么 pthread_cond_wait()
几乎总是必须在检查条件的循环中执行。