2011-08-03 65 views
0

我的程序似乎有一个死锁问题。pthread_cond_wait()不释放互斥锁的可能原因?

基本上我有一个类,它看起来像这样:

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唯一的公共接口(不包括构造函数和析构函数)。它还需要获取它的执行中的互斥量。我的症状是bar()永远无法获得mutex_。它看起来像pthread_cond_wait()不会像它应该那样释放互斥锁。如果我禁用显示器线程(因此没有赛车状况),那么bar()可以运行到完成没有任何问题。

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

+0

顺便说一句,'mutex_'和'cv_'已经正确地初始化了,在构造函数中属性都是NULL。 –

+0

使用pthreads没有什么明显的错误。你能告诉我们构造函数吗? –

回答

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

} 
+0

这太奇怪了。我刚刚重新启动,做了一个“干净”,然后重新制作。令人惊讶的是,它的工作。我仍然无法弄清楚为什么。也许这是操作系统资源耗尽。无论如何,你所说的“意外复制一个物体”会给我很多警告。我会选择接受。谢谢。 –

0

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

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

假设,条件是假的。你输入while循环,并在第一次运行一切正常,即你解锁互斥体并等待决定变量。条件变量是否会发生变化,而不是布尔型条件?在这种情况下,你会输入pthread_cond_wait和一个未初始化的互斥体,并且可能会发生未定义的行为... 我想如果你还会显示bar()方法,它会有所帮助。

另一个猜测是线程优先级。也许插入一个良率让线程有更好的切换机会。

+0

不,那不是。如果cv被发信号通知,则在返回pthread_cond_wait之前将重新获取该互斥信号。然后它会循环(因为条件仍然是错误的),然后释放锁并再次等待。事实上,我看到许多使用if的错误实现,并且无法处理允许发生的虚假唤醒。 –

+0

谢谢,@KPK。我认为你指的是虚假的唤醒,因为@ dave-s也建议。因为我在这里使用while循环,所以这不太可能是原因。显示'bar()'不会有帮助,因为我的跟踪显示从'pthread_mutex_lock()'开始的'bar()'中的代码从来没有机会被执行。你也建议我产生线程。收益谁呢? –

0

万一遇到此,我再次碰到了,我也陷入了僵局,在那里我期待cond_wait释放互斥体,其他线程可以锁定互斥非常相似的情况。

我的问题是,我已经设置互斥为递归(与settype-> PTHREAD_MUTEX_RECURSIVE_NP),并在cond_wait调用之前错误地锁定了两次互斥锁。由于cond_wait只解锁一次,互斥锁仍然被锁定。明显的解决办法是只锁定一次。另外,作为一个教训,我不会使用递归互斥设置,除非我真的需要。