Нет такой вещи, как уничтожение потока.
Плохо названная функция pthread_kill
является аналогом потока плохо названной функции kill
, которая отправляет сигнал на обработку.Название kill
исторически имело смысл в том смысле, что действие многих сигналов по умолчанию - убить процесс.Но это действие по умолчанию для уничтожения процесса не зависит от того, был ли сигнал отправлен процессу или конкретному потоку - в любом случае процесс завершается.
Единственное время pthread_kill
полезно, когда вы хотите вызвать обработчик сигнала в другом потоке.Если вы не уверены, что обработчик сигнала не мог прервать какую-либо функцию, которая не безопасна для асинхронного сигнала, обработчик сигнала ограничен вызовом функций, которые безопасны для асинхронного сигнала и, следовательно, не может даже действовать, чтобы завершить время жизни потока (pthread_exit
не безопасен для асинхронных сигналов).
Если вы согласны с тем, что поток, в конечном итоге, завершается в результате вызова, pthread_cancel
- это правильный способ завершить поток, застрявший в блокировке.операция.Тем не менее, чтобы использовать его безопасно, вам нужно интенсивно использовать pthread_cleanup_push
и pthread_cleanup_pop
.
Если вы не хотите, чтобы поток завершался, сигналы - это единственный вариант.У вас есть два варианта:
Установить обработчик сигнала (может быть недоступен), используя sigaction
без SA_RESTART
, так что это вызывает EINTR
.Так как в этом подходе есть неотъемлемые условия гонки (если вы посылаете сигнал непосредственно перед тем, как вводится системный вызов блокировки, а не после того, как он заблокирован, сигнал ничего не будет делать), вам нужно повторно отправить сигналс экспоненциальным откатом, чтобы не истощать цель времени выполнения, пока цель не подтвердит с помощью какого-либо другого механизма синхронизации (хорошо работает семафор POSIX), что она получила сообщение.
Установите обработчик сигнала, который будет longjmp
.Чтобы сделать это безопасно, вам нужно контролировать контекст, из которого это может произойти;Самый простой способ сделать это - сохранить его в маске сигнала в обычном режиме, сняв маску только тогда, когда jmp_buf
действителен для блокирующего вызова.Функция блокировки, которую вы вызываете, должна быть безопасна для асинхронных сигналов, и не должна быть той, которая выделяет или освобождает ресурсы (например, open
или close
), поскольку вы потеряете знанияо том, завершил ли он при обработке сигнала.Конечно, jmp_buf
, или указатель на него, должен быть локальным для потока объектом (_Thread_local
/ __thread
), чтобы это работало вообще.