【问题标题】:why does pthread_cond_signal cause deadlock为什么 pthread_cond_signal 会导致死锁
【发布时间】:2015-03-09 10:36:55
【问题描述】:

我是条件变量的新手,如果不使用pthread_cond_broadcast(),就会出现死锁。

#include <iostream>
#include <pthread.h>

pthread_mutex_t m_mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;

bool ready = false;

void* print_id (void *ptr )
{
    pthread_mutex_lock(&m_mut);
    while (!ready) pthread_cond_wait(&cv, &m_mut);
    int id = *((int*) ptr);
    std::cout << "thread " << id  << '\n';
    pthread_mutex_unlock(&m_mut);
    pthread_exit(0);
    return NULL;
}

这里的条件变了!

void go() {
    pthread_mutex_lock(&m_mut);
    ready = true;
    pthread_mutex_unlock(&m_mut);
    pthread_cond_signal(&cv);
}

如果我把go()的最后一行改成pthread_cond_broadcast(&amp;cv);就可以了

int main ()
{
    pthread_t threads[10];

    // spawn 10 threads:
    for (int i=0; i<10; i++)
        pthread_create(&threads[i], NULL, print_id, (void *) new int(i));

    go();

    for (int i=0; i<10; i++) pthread_join(threads[i], NULL);

    pthread_mutex_destroy(&m_mut);
    pthread_cond_destroy(&cv);

    return 0;
}

预期的答案(任意顺序)是

thread 0

....

thread 9

但是,在我的机器 (ubuntu) 上,它什么也没打印。 谁能告诉我原因?谢谢。

【问题讨论】:

  • 是的。 _signal 唤醒等待列表中的任意线程。我错过了什么吗?
  • “但是……它什么也没打印。” 真的吗?乍一看,我很怀疑。假设 stdout 是行缓冲的(例如,终端),我理解为什么程序可能会打印 1 到 10 行输出,但不能打印零行输出。如果某些线程比main 快,那么至少其中一个线程将被发出信号并因此产生输出。如果某些线程比main 慢,他们会发现ready 已经准备好,并且每个线程都输出一行。

标签: c++ c pthreads mutex condition-variable


【解决方案1】:

来自手册页(我强调):

pthread_cond_signal 重新启动在条件变量cond 上等待的线程之一。如果没有线程在 cond 上等待,则不会发生任何事情。 如果有多个线程在 cond 上等待,则只重启一个,但没有指定是哪个。

pthread_cond_broadcast 重新启动所有等待条件变量cond 的线程。如果没有线程在 cond 上等待,则不会发生任何事情。

十个线程中的每一个都在相同的条件下等待。您只调用一次go() - 来自main()。这会调用pthread_cond_signal,它只会发出一个线程(任意一个)的信号。所有其他人仍将等待,因此pthread_join 挂起,因为它们不会终止。当你切换到pthread_cond_broadcast时,所有的线程都会被触发。

【讨论】:

  • 在我的代码中,线程必须先获取互斥体,然后才能等待条件变量。我以为只有一个线程可以等待cv,对吗?
  • 是的。 pthread_cond_wait 要求互斥锁在进入时被锁定并自动解锁,在退出时重新锁定。
  • 嗯,我还是不明白为什么它什么也没打印。十个线程是否在 cv 上等待?如果他们这样做,为什么我不能使用 _signal?
  • 我不能告诉你是否所有十个线程都在等待cv,因为你没有显示所有的代码,但我只能假设这就是正在发生的事情。如果他们都打电话给print_id,那么是的。如果是这样,pthread_cond_signal 将无法工作,因为它会随机触发其中一个等待线程,而您只调用一次go(),因此只会触发一个。
  • 实际上是的,您已经展示了足够多的代码来证明这绝对是问题所在。我会修改我的答案。
猜你喜欢
  • 1970-01-01
  • 2019-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 1970-01-01
相关资源
最近更新 更多