我的程序似乎遇到了死锁问题。
基本上我有一个看起来像这样的课程:
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。我怀疑这种僵局情况是否还有其他原因。任何人都可以提供这方面的线索吗?谢谢!
答案 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只解锁了一次,因此互斥锁仍然被锁定。显而易见的解决办法是只锁定一次。另外,作为一个经验教训,除非我真的需要,否则我不会使用递归互斥设置。