避免在pthread_cond_wait和pthread_cond_signal时死锁

avoiding deadlock when pthread_cond_wait and pthread_cond_signal

本文关键字:pthread cond signal 死锁 wait      更新时间:2023-10-16

我有一个关于使用pthread条件变量的问题。一般用例是这样的

//thread 1:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
do_something()
pthread_mutex_unlock(&mutex);
//thread 2:
pthread_cond_signal(&cond);  

现在我知道pthead_cond_wait将解锁互斥锁并进入睡眠状态,当唤醒时,它将锁定互斥锁,然后从调用返回,但如何确保线程2的信号在线程1处于等待状态后到达线程1。可能出现thread2先运行,然后thread1导致丢失唤醒的情况。

如果我再次在线程2中使用互斥锁,那么也可能发生thread2将获得锁,它将发出信号,而thread1仍在尝试获取锁。这将再次导致丢失唤醒。

如何确保来自条件变量的信号到达等待它的线程?

谢谢

你的"通用用例"是不正确的。条件变量必须与某个共享状态的条件配对,称为谓词一般用例是:

线程1:

pthread_mutex_lock(&mutex);
while (!condition)
    pthread_cond_wait(&cond, &mutex);
do_something(); /* Requiring 'condition' to be true */
pthread_mutex_unlock(&mutex);
线程2:

pthread_mutex_lock(&mutex);
do_something_else(); /* That sets 'condition' true */
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);

…其中condition在某些由mutex保护的共享状态上,例如,condition可能正在检查共享队列是否为非空。

在这个结构中不会有丢失的唤醒,因为等待线程总是在等待前检查条件。如果条件已经为真,它不会等待——因为它持有保护条件的互斥锁,所以在检查和等待之间也不能变为真。

(注意pthread_cond_broadcast()通常是正确的函数,pthread_cond_signal()是在许多情况下适用的优化)。

这完全取决于你的设计。您可以使用bool变量(例如issignals)来同步两者。以下内容(请参考)

//thread 1:
pthread_mutex_lock(&mutex);
if(isSignalled == 0){
    pthread_cond_wait(&cond, &mutex);
}
isSignalled = 0;
do_something()
pthread_mutex_unlock(&mutex);
//thread 2:
pthread_mutex_lock(&mutex);
isSignalled = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);