Тупик при выходе многопоточного процесса из обработчика сигнала - PullRequest
0 голосов
/ 11 февраля 2019

Есть два потока в процессе.когда основной поток получает 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 голосов
/ 11 февраля 2019

Я предполагаю, что вы отправляете сигнал в другой поток, потому что вы хотите выполнить некоторую работу, которая не может быть выполнена с помощью асинхронно-безопасных функций.

Проблема заключается в том, что если ваш обработчик сигнала вызывается наПоток, у которого были получены какие-либо блокировки (например, в вашем случае, внутренняя блокировка списка libio), тогда любой поток, который пытается получить такую ​​же блокировку, будет блокироваться бесконечно: вы не можете вернуться из обработчика SIGSEGV, поэтому блокировка никогда не станет доступной дляблокировка снова, и ни один поток, ожидающий блокировки, не будет прогрессировать.В вашем случае, функция exit должна получить блокировку списка libio, потому что она должна пройти через список всех открытых потоков файлов и очистить их, в то время как поток, открывающий новый файл, получает блокировку, в то время как он устанавливает новый файл всписок.

Несмотря на то, что это деталь реализации, которую можно было бы рассмотреть внутри glibc в какой-то (далекой) точке в будущем (небольшие улучшения, которые мы сделали относительно недавно, не помогут в вашем случае), единственнымВы можете вызвать _exit перед завершающей процедурой выхода из процесса в glibc, после очистки, которую вам нужно сделать.В вашем случае это можно сделать с помощью обработчика atexit, который вы зарегистрировали как можно раньше, но это зависит от вашего приложения.

Что касается обработчиков сбоя, мы опубликовали здесь несколько советов:

В статье рассматривается fork, но проблемы взаимоблокировок практически одинаковы в вашем случае.

...