2016-12-07 70 views
2

请考虑使用pthread的基本多线程程序。 我们有一个主线程,创建另一个线程来完成一些工作。虚假唤醒后的互斥状态

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-clause检查谓词的等待,即使我们知道没有人应该这样做。

现在,如果在子线程正在工作时,主线程中发生虚假唤醒,那么互斥量m的状态是什么?主线程是否拥有它,而不是先让孩子解锁它,这样既拥有它呢?

或者一个虚假的唤醒只跳过等待条件,但不等待互斥锁被释放?

+1

当['pthread_cond_wait()'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html)成功返回时,当前线程锁定了互斥锁,而不管唤醒是否为虚假或不。如果不满意的话,负责人会在唤醒线程中仔细检查条件,再等待。 –

+0

所以我们可以在技术上考虑这两个线程在那一刻拥有互斥量? – JMC

+0

否;只有一个线程锁定了互斥锁 - 您不能同时锁定互斥锁,因为它不会是互斥锁。广播不会改变互斥体的互斥属性。 –

回答

2

pthread_cond_wait()调用在某些其他线程持有关联的互斥锁时不能'虚拟'唤醒。当pthread_cond_wait()成功返回时,它将声明该互斥体,因此只有互斥体可用时才能成功返回。

在你的榜样,会出现虚假唤醒可能发生,因为foo()可以调用pthread_cond_wait()并有伪唤醒之前child()永远都有机会打电话pthread_mutex_lock()摆在首位。

在你的例子中的另一个问题(注释代码被禁用)具有的是,有可能pthread_cond_wait()调用从未唤醒。如果child()foo()设法获取互斥锁之前完成了它的所有处理,则可能发生这种情况。在这种情况下,child()将在主线程在pthread_cond_wait()中等待之前调用pthread_cond_broadcast(),因此主线程将错过广播。由于foo()从不检查done同时持有互斥量,它不会注意到child()已完成其工作。

这就是为什么pthread_cond_wait()几乎总是必须在检查条件的循环中执行。

+0

谢谢。在你回答之前,我曾经评论说我认为这是事实,你已经确切地证实了这一点。 while循环仍然需要。 – JMC

+0

在第二段中,您说可能会发生虚假唤醒,因为'child()'可以锁定互斥锁之前'foo()'调用'pthread_cond_wait()'。这怎么会发生?在孩子锁定互斥之前,执行计算,广播条件并解锁互斥锁之前,什么可以表示状态? AFAICS,'foo()'当然可以调用'pthread_cond_wait()',但它会被挂起(并且解锁互斥锁),直到子进程处理成功。 –

+0

'永不醒目'的情景是一个真正的问题;如果孩子先运行,'foo()'中的互斥锁将会失败,直到孩子在处理后解锁互斥体,并且因此广播确实发生在'foo()'不在'pthread_cond_wait()'中。什么是同步事件的批准/正常途径,以便'child()'获取互斥体之前'foo()'挂在'pthread_cond_wait()'中? –

相关问题