在信号处理程序中退出多线程进程时出现死锁

时间:2019-02-11 17:46:52

标签: multithreading pthreads signals deadlock signal-handling

一个进程中有两个线程。当主线程从信号处理程序接收SEGV时,我曾使用pthread_kill将内部信号发送到其他辅助线程,并使用此内部信号将辅助线程捕获在睡眠状态,因此我现在可以执行强制性清理和堆栈跟踪转储考虑到现在的单线程进程(因为其他辅助线程处于睡眠状态)从主线程导入文件。

但是,一旦我在主线程退出时遇到该问题,就向左处理(不退出)并且似乎 在两个线程之间处于死锁状态。

请帮助我为什么以及哪部分代码导致死锁。

预先感谢!

Auxiliary Thread stack:

Thread 2 (Thread 0x7fc565b5b700 (LWP 13831)):
#0  0x00007fc5668e81fd in nanosleep () from /lib64/libc.so.6
#1  0x00007fc566915214 in usleep () from /lib64/libc.so.6
#2  0x00000000009699a2 in SignalHandFun() at ...........
#3  <signal handler called>
#4  0x00007fc56691820a in mmap64 () from /lib64/libc.so.6
#5  0x00007fc5668a5bfc in _IO_file_doallocate_internal () from /lib64/libc.so.6
#6  0x00007fc5668b386c in _IO_doallocbuf_internal () from /lib64/libc.so.6
#7  0x00007fc5668b215b in _IO_new_file_underflow () from /lib64/libc.so.6
#8  0x00007fc5668b38ae in _IO_default_uflow_internal () from /lib64/libc.so.6
#9  0x00007fc566894bad in _IO_vfscanf_internal () from /lib64/libc.so.6
#10 0x00007fc5668a2cd8 in fscanf () from /lib64/libc.so.6
..... 
......
.....
#15 0x00007fc567259806 in start_thread () from /lib64/libpthread.so.0
#16 0x00007fc56691b64d in clone () from /lib64/libc.so.6
#17 0x0000000000000000 in ?? ()

Main Thread stack:

Thread 1 (Thread 0x7fc5679c0720 (LWP 13795)):
#0  0x00007fc56692878e in __lll_lock_wait_private () from /lib64/libc.so.6
#1  0x00007fc5668b504b in _L_lock_1309 () from /lib64/libc.so.6
#2  0x00007fc5668b3d9a in _IO_flush_all_lockp () from /lib64/libc.so.6
#3  0x00007fc5668b4181 in _IO_cleanup () from /lib64/libc.so.6
#4  0x00007fc566872630 in __run_exit_handlers () from /lib64/libc.so.6
#5  0x00007fc5668726b5 in exit () from /lib64/libc.so.6
#6  0x00000000009698e3 in SignalHandFun() at ....
#7  <signal handler called>
#8  0x000000b1000000b0 in ?? ()
#9  0x0000000000000000 in ?? ()

1 个答案:

答案 0 :(得分:0)

我假设您将信号发送到另一个线程,因为您想做一些异步信号安全功能无法完成的工作。

问题是,如果在获取了任何锁的线程上调用信号处理程序(例如,内部libio列表锁),那么任何试图获取同一锁的线程都将无限期地阻塞:无法从您的SIGSEGV处理程序返回,因此该锁将永远无法再次用于锁定,并且等待该锁的线程也不会取得进展。在您的情况下,exit函数需要获取libio列表锁,因为它必须遍历所有打开的文件流的列表并刷新它们,而打开新文件的线程则在获取新文件时获取了该锁。列表中的文件。

尽管这是实现的详细信息,并且可以想象在将来的某个(远)点在glibc中解决(我们最近所做的小改进对您的情况无济于事),唯一的方法是调用{ {1}}在glibc中的最终进程退出过程之前,在清理之后需要执行。对于您而言,可以通过您早日注册的_exit处理程序来执行此操作,但这取决于您的应用程序。

关于崩溃处理程序,我们在此处发布了一些建议:

本文的重点是atexit,但是死锁问题与您的情况几乎相同。

相关问题