1

在以下链接中: 为什么 pthread 的条件变量函数需要互斥锁?

@nos 描述了在没有互斥体的情况下实现 pthread_cond_wait() 的潜在漏洞:

while(1) {
    pthread_cond_wait(&cond); //imagine cond_wait did not have a mutex
    pthread_mutex_lock(&mutex);
    char *data = some_data;
    some_data = NULL;
    pthread_mutex_unlock(&mutex);
    handle(data);
}

“行不通,在醒来和抓住互斥锁之间仍有可能出现竞争条件。”

我不明白唤醒和获取互斥锁之间的竞争条件是如何产生的?

4

1 回答 1

0

实际上,该示例并未显示该问题,但作为一般原则,当有两条指令时,存在竞争条件

这是一个希望能说明问题的例子。

假设您自己管理互斥锁,并且您有两个线程thread#1thread#2

  • thread#1需要修改一些共享状态
  • 它获取互斥体并更改状态
  • 它释放互斥体并在继续之前等待某些事情发生

这是一些代码:

    pthread_mutex_lock(&mutex);
    // change state
    pthread_mutex_unlock(&mutex);
    pthread_cond_wait(&cond);

还有更多:

  • 线程#2等待互斥体,更改共享状态并使用条件变量向线程#1 发出信号,让线程#1在继续之前有机会做某事

这是代码:

    pthread_mutex_lock(&mutex);
    // change state
    pthread_mutex_unlock(&mutex);
    pthread_cond_signal(&cond);

这是一个令人讨厌的场景:

  • thread#1获取锁并改变共享状态
  • thread#1释放锁, pthread_mutex_unlock(&mutex), 并被抢占
  • 线程#2获取锁,pthread_mutex_lock(&mutex)更改状态,解锁,发出信号并被抢占
  • 线程#1再次被调度并等待条件,pthread_cond_wait(&cond)

您有一个问题可能会升级:

  • 信号已丢失:它本身可能或多或少取决于您的应用程序
  • 但即使信号本身并不重要,线程#1现在也在等待已经发生的信号
  • 即使线程#1没有做一些重要的事情,如果后面的线程#2等待线程#1 ,你也可能会出现死锁

因此,为了避免这个问题,线程#1必须在任何其他线程有机会发出条件信号之前在释放锁时立即等待。

恕我直言,它更多的是解锁/等待转换,而不是需要原子的唤醒/锁定转换。

我很好奇唤醒/锁定转换绝对需要原子的场景......

希望这可以帮助。

于 2013-11-11T00:39:34.290 回答