我有一个程序,当其中一个线程调用时会死锁pthread_cond_siganl
(或广播)。
该问题在主程序中可以 100% 重现。我无法弄清楚它出了什么问题,因此提取了调用 wait 和 signal 的代码段。然而,僵局cannot与提取的问题一起重现。
Running valgrind
主程序上不会报告任何无效的读/写或内存泄漏。
我想知道调用时出现死锁的可能原因有哪些pthread_cond_signal
.
提取的片段如下。
#include <pthread.h>
#include <math.h>
#include <syscall.h>
#include <assert.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
void Task() {
cerr << syscall(SYS_gettid) << " In Task, sleeping..." << endl;
sleep(5);
}
pthread_mutex_t lock;
pthread_cond_t cond;
bool doingTheTask= false;
void* func(void* ) {
pthread_mutex_lock(&lock);
if (doingTheTask) {
cerr << syscall(SYS_gettid) << " wait... " << endl;
while ( doingTheTask) {//spurious wake-up
cerr << syscall(SYS_gettid) << " waiting..." << endl ;
pthread_cond_wait(&cond, &lock);
cerr << syscall(SYS_gettid) << " woke up!!!" << endl ;
}
}
else {
cerr << syscall(SYS_gettid) << " My Turn to do the task..." << endl;
assert( ! doingTheTask );
doingTheTask= true;
pthread_mutex_unlock(&lock);
Task();
cerr << syscall(SYS_gettid) << " Before trying to acquire lock" << endl;
pthread_mutex_lock(&lock);
cerr << syscall(SYS_gettid) << " After acquiring lock" << endl ;
assert( doingTheTask );
doingTheTask = false;
cerr << syscall(SYS_gettid) << " Before broadcast" << endl;
pthread_cond_broadcast(&cond);
cerr << syscall(SYS_gettid) << " After broadcast" << endl;
}
pthread_mutex_unlock(&lock);
return NULL;
}
int main() {
pthread_mutex_init(&lock,NULL);
pthread_cond_init(&cond,NULL);
pthread_t thread[2];
for ( int i = 0 ; i < 2 ; i ++ ) {
if (0 != pthread_create(&thread[i], NULL, func, NULL) ) {
cerr << syscall(SYS_gettid) << " Error creating thread" << endl;
exit(1);
}
}
for ( int i = 0 ; i < 2 ; i ++ ) {
pthread_join(thread[i],NULL);
}
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
return 0;
}
唯一重要的部分是 func 函数。其他部分只是为了编译而呈现。
正如我所说的问题在此程序中无法重现。
该代码片段与主程序的区别在于:
- 在主程序中,
mutex
and condvar
是成员字段,函数是成员方法。
- 该任务执行一些任务而不是睡觉。
- 多个线程可能会等待,我们应该广播而不是发出信号。然而,即使我使用信号和一个等待线程,死锁也是 100% 可重现的。
我试图用这段代码解决的问题是一种机制,当至少一个线程需要完成该任务时,该机制会执行一次该任务。但是任何两个线程都不应该并行执行该任务,一旦其中一个线程执行了该任务,其他线程就不需要执行该任务。此方法的客户端假设它会阻塞直到任务完成(因此我在看到有人正在执行任务后无法立即返回)。
死锁线程的回溯是:
#0 __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:136
#1 0x00007ffff73e291c in pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:259
and
#0 __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:136
#1 0x00007ffff73e30b1 in pthread_cond_signal@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S:142
pthread_cond_signal 死锁 https://stackoverflow.com/questions/4345315/pthread-cond-signal-deadlocks是一个类似的问题。但似乎提出问题的人有记忆损坏。我没有内存损坏(说valgrind
).
该问题在我测试的两台机器上 100% 可重现。 (ArchLinux 最新版和 Uubntu 10.04.3)。
主程序的示例输出如下。它再次表明线程在调用之前阻塞pthread_cond_wait
and pthread_cond_signal
。 (第一列显示线程 ID)。
3967 In Task, sleeping...
3967 My Turn to do the task...
3967 In Task, sleeping...
3973 wait...
3973 waiting...
3976 <output from some other thread>
3967 Before trying to acquire lock
3967 After acquiring lock
3967 Before broadcast
主程序是用C++编写的。但我使用的是该语言的 C 部分,因此避免使用 C++ 标签。