虚假唤醒后的互斥体状态

时间:2016-12-07 00:41:18

标签: c multithreading pthreads mutex condition-variable

使用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子句检查谓词的情况下实现等待,即使我们知道没有人应该这样做。

现在,如果在子线程正在执行其工作时,主线程中发生虚假唤醒,互斥锁的状态将是什么?主线程是否会在没有孩子首先解锁它的情况下拥有它,所以它们都拥有它?

或者,虚假的唤醒只是跳过等待条件,而不是等待释放互斥锁?

1 个答案:

答案 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()几乎总是必须在检查条件的循环中执行。