【问题标题】:avoiding deadlock when pthread_cond_wait and pthread_cond_signal在 pthread_cond_wait 和 pthread_cond_signal 时避免死锁
【发布时间】:2015-08-18 16:07:42
【问题描述】:

我有一个关于使用 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。可能会出现线程 2 先运行,然后线程 1 导致丢失唤醒的情况。

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

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

谢谢

【问题讨论】:

  • 您可以通过不使用条件变量作为谓词来确保这一点。它们用于表示某些谓词中的更改;不是谓词本身。 read this 虽然关系模糊,但它在如何使用 cvar、互斥锁和谓词更改方面有一些微不足道但很重要的方面。

标签: c++ pthreads


【解决方案1】:

它完全基于您的设计。 您可以使用布尔变量(例如 isSignalled)来同步两者。像下面这样的东西(请把它当作一个想法)

//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);

【讨论】:

  • 你需要使用while (isSignalled == 0)而不是if(),因为pthread_cond_wait()被允许虚假唤醒。
【解决方案2】:

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

线程 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() 是适用于许多情况的优化)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    相关资源
    最近更新 更多