Как правильно завершить поток в обработчике сигнала?
Я хочу установить обработчик сигналов для SIGSEGV, SIGILL и, возможно, нескольких других сигналов, которые вместо завершения всего процесса просто завершают поток, который нарушает работу, и, возможно, устанавливают флаг где-то, чтобы поток мониторинга мог пожаловаться и запустить другой поток. Я не уверен, что есть безопасный способ сделать это. Pthreads, кажется, предоставляет функции для выхода из текущего потока, а также для отмены другого потока, но они потенциально могут вызывать несколько обработчиков при выходе. Даже если они этого не делают, кажется, что существует много ситуаций, в которых они не защищены от асинхронных сигналов, хотя возможно, что таких ситуаций можно избежать. Есть ли функция более низкого уровня, которую я могу вызвать, которая просто разрушает поток? Предполагая, что я изменяю свои собственные структуры данных безопасным для асинхронного сигнала способом и не получаю мьютексы, существуют ли pthread/ другие глобальные структуры данных, которые могут остаться в несогласованном состоянии просто потоком, заканчивающимся на SIGSEGV? На ум приходит malloc, но сам malloc не должен SIGSEGV/SIGILL, если libc не глючит. Я понимаю, что POSIX здесь очень консервативен и не дает никаких гарантий. Пока есть способ сделать это на практике, я счастлив. Форкинг не вариант, кстати.
1 ответ
Если SIGSEGV
/SIGILL
/так далее. происходит в вашем собственном коде, обработчик сигнала не будет работать в контексте асинхронного сигнала (это принципиально синхронный сигнал, но все равно будет контекстом AS, если это происходит внутри стандартной библиотечной функции), так что вы можете легально вызвать pthread_exit
из обработчика сигнала. Однако, есть все еще проблемы, которые делают эту практику сомнительной:
SIGSEGV
/SIGILL
/так далее. никогда не встречаются в программе, чье поведение определено, если вы не генерируете их черезraise
,kill
,pthread_kill
,sigqueue
и т. д. (и в некоторых из этих особых случаев это будут асинхронные сигналы). В противном случае они указывают на то, что программа имеет неопределенное поведение. Если программа вызвала неопределенное поведение, все ставки отключены. UB не изолирован от определенного потока или определенной последовательности во времени. Если в программе есть UB, весь ее вывод / поведение не имеет смысла.Если состояние программы повреждено (например, из-за
free
, использование недопустимых указателей, переполнение буфера, ...) очень возможно, что первый ошибочный доступ произойдет внутри части стандартной библиотеки (например, внутриmalloc
), а не в вашем коде. В этом случае обработчик сигнала работает в безопасном для AS контексте и не может вызватьpthread_exit
, Конечно, в любом случае в программе уже есть UB (см. Выше), но даже если вы хотите сделать вид, что это не проблема, у вас все равно будут проблемы.
Если ваша программа испытывает такие сбои, вам нужно найти причину и устранить ее, а не пытаться обойти ее обработчиками сигналов. Вальгринд твой друг. Если это невозможно, лучше всего выделить код сбоя в отдельные процессы, где вы можете рассуждать о том, что произойдет, если они произойдут сбой асинхронно, а не иметь код сбоя в том же процессе (где дальнейшие рассуждения о поведении кода недопустимы как только ты знаешь, что это вылетает).