pthread_cond_wait()未发布互斥锁的可能原因?

时间:2011-08-03 02:28:32

标签: c++ pthreads deadlock

我的程序似乎遇到了死锁问题。

基本上我有一个看起来像这样的课程:

class Foo {
public:
  Foo();

  void bar();

private:
  void monitor();

  bool condition_;
  pthread_t monitor_;
  pthread_mutex_t mutex_;
  pthread_cond_t cv_;
};

Foo的构造函数中,我在一个单独的线程(即monitor())中调用monitor_。此monitor()函数执行以下操作:

pthread_mutex_lock(&mutex_);
while (true) {
  while (!condition_) {
    pthread_cond_wait(&cv_, &mutex_);
  }
  // do something
  // and then setting condition_ to false
  condition_ = false;
}
pthread_mutex_unlock(&mutex_);

bar()函数是Foo唯一的公共接口(不包括ctor和dtor)。它还需要在执行时获取互斥锁。我的症状是bar()永远无法获得mutex_。看起来pthread_cond_wait()不会像预期那样释放互斥锁。如果我禁用了监视器线程(因此没有竞争条件),那么bar()可以毫无问题地运行到它的完成。

当然,上面的代码是我真实代码的简化版本。实际上我认为这段代码中没有逻辑错误,我正确使用pthread。我怀疑这种僵局情况是否还有其他原因。任何人都可以提供这方面的线索吗?谢谢!

3 个答案:

答案 0 :(得分:0)

我敢打赌它在这里失败了:

while (!condition_) {
    pthread_cond_wait(&cv_, &mutex_);
}

我们假设,条件为假。你进入while循环,在第一次运行中一切都很顺利,即你解锁互斥锁并等待决策变量。是否会发生条件变量而不是布尔条件?在这种情况下,您将使用未初始化的互斥锁输入pthread_cond_wait,并且可能会发生未定义的行为... 我想如果你也会显示bar()方法会有所帮助。

另一个猜测是线程优先级。也许插入一个yield来给线程提供更好的切换机会。

答案 1 :(得分:0)

我会查看你的构造函数和bar()函数,并且可能是你不小心制作了有问题的对象的副本。我复制了你提供的课程,以及我对其余部分如何运作的假设。下面的程序每秒唤醒,并发出信号。

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

class Foo {
public:
  Foo() {
    condition_ = false;
    pthread_mutex_init(&mutex_, NULL);
    pthread_cond_init(&cv_, NULL);
    pthread_create(&monitor_, NULL,
           startFunc, this);
  }

  void bar() {
    pthread_mutex_lock(&mutex_);
    std::cout << "BAR" << std::endl;
    condition_ = true;
    pthread_cond_signal(&cv_);
    pthread_mutex_unlock(&mutex_);
  }

private:
  Foo(const Foo&) {};
  Foo& operator=(const Foo&) { return *this; };

  static void* startFunc(void* r) {
    Foo* f = static_cast<Foo*>(r);
    f->monitor();
    return NULL;
  }

  void monitor() {
    pthread_mutex_lock(&mutex_);
    while (true) {
      while (!condition_) {
    pthread_cond_wait(&cv_, &mutex_);
      }
      // do something
      // and then setting condition_ to false
      std::cout << "FOO" << std::endl;
      condition_ = false;
    }
    pthread_mutex_unlock(&mutex_);

  }

  bool condition_;
  pthread_t monitor_;
  pthread_mutex_t mutex_;
  pthread_cond_t cv_;
};


int main() {
  struct timespec tm = {1,0};
  Foo f;

  while(true) {
    f.bar();
    nanosleep(&tm, NULL);
  }

}

答案 2 :(得分:0)

如果再遇到这种情况,我遇到了一个非常类似的情况,我遇到了死锁,我期待cond_wait释放互斥锁,以便其他线程可以锁定互斥锁。

我的问题是我将互斥锁设置为递归(使用settype-&gt; PTHREAD_MUTEX_RECURSIVE_NP)并且在cond_wait调用之前错误地锁定了互斥锁两次。由于cond_wait只解锁了一次,因此互斥锁仍然被锁定。显而易见的解决办法是只锁定一次。另外,作为一个经验教训,除非我真的需要,否则我不会使用递归互斥设置。