gpt4 book ai didi

c - pthread_cond_signal 导致死锁

转载 作者:可可西里 更新时间:2023-11-01 11:50:32 25 4
gpt4 key购买 nike

我有一个程序在其中一个线程调用 pthread_cond_siganl(或广播)时死锁。该问题在主程序中可 100% 重现。我无法弄清楚它有什么问题,因此提取了调用 wait 和 signal 的代码段。但是,死锁不能用提取的问题重现。

在主程序上运行 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 函数。其他部分只是为了编译而呈现。

正如我所说,问题在此程序中不可重现。这段代码和主程序的区别是:

  • 在主程序中,mutexcondvar是成员字段,function是成员方法。
  • 任务做一些任务而不是休眠。
  • 多个线程可能会等待,我们应该广播而不是发信号。但是,即使我使用信号和一个等待线程,死锁也是 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

#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 deadlocks是一个类似的问题。但似乎提出问题的人有内存损坏。我没有内存损坏(valgrind)。

问题在我测试过的两台机器上 100% 重现。 (最新的 ArchLinux 和 Uubntu 10.04.3)。

主程序的示例输出如下。它再次显示线程在调用 pthread_cond_waitpthread_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++ 标记。

最佳答案

愚蠢的错误。在执行信号和等待之前,我正在销毁 mutexcondvar。要重现,只需在主函数中加入线程之前移动销毁函数。

令人惊讶的是,在我的两台机器上,这会产生 100% 一致(和错误)的行为。

关于c - pthread_cond_signal 导致死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8248458/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com