pthread_exit() в обработчике сигналов
(Этот вопрос может быть в некоторой степени связан с pthread_exit в обработчике сигналов, который вызывает ошибку сегментации.) Я пишу библиотеку предотвращения блокировок, где всегда есть поток проверки, выполняющий графическую работу, и проверяет, есть ли взаимоблокировка, если это так, то он сигнализирует об одном из конфликтующие темы. Когда этот поток ловит сигнал, он освобождает все мьютексы, которые он имеет и выходит. Существует несколько мьютексов ресурсов (очевидно) и один мьютекс критической области, все вызовы для получения, снятия блокировки ресурсов и выполнения вычислений графа должны сначала получить эту блокировку. Теперь проблема идет. С 2 конкурирующими (не считая проверяющего потока) потоками, иногда программа блокируется после того, как один поток будет уничтожен. В gdb говорится, что мертвый поток владеет блокировкой критической области, но никогда не снимал ее. После добавления точки останова в обработчике сигнала и пошагового выполнения кажется, что блокировка принадлежит кому-то другому (как и ожидалось) прямо перед pthread_exit(), но владение магическим образом переходит в этот поток после pthread_exit()..
Единственное предположение, о котором я могу думать, это то, что поток, который нужно убить, блокировал pthread_mutex_lock при попытке получить блокировку критической области (потому что ему требовался другой мьютекс ресурса), затем пришел сигнал, прервавший pthread_mutex_lock. Поскольку этот вызов не защищен от сигнала, что-то странное случилось? Как обработчик сигнала мог вернуться, и этот поток получил блокировку, а затем вышел? ИДК. Любое понимание приветствуется!
1 ответ
pthread_exit
не является безопасным для асинхронного сигнала, и, таким образом, единственный способ вызвать его из обработчика сигнала - это убедиться, что сигнал не прерывает никакую функцию, не безопасную для асинхронного сигнала.
Как правило, использование сигналов в качестве метода связи с потоками обычно является действительно плохой идеей. Вы в конечном итоге смешаете две проблемы, которые уже сами по себе достаточно сложны: безопасность потоков (правильная синхронизация между потоками) и повторный вход в один поток.
Если ваша цель с сигналами - просто дать команду потоку завершиться, лучше использовать механизм pthread_cancel
, Однако, чтобы использовать это безопасно, поток, который будет отменен, должен установить обработчики отмены в соответствующих точках и / или временно отключить отмену, когда это небезопасно (с помощью pthread_setcancelstate
). Также имейте в виду, что pthread_mutex_lock
не является точкой отмены. Не существует безопасного способа прервать поток, который заблокирован, в ожидании получения мьютекса, поэтому, если вам нужна прерывистость, подобная этой, вам, вероятно, потребуется либо более сложная настройка синхронизации с условными переменными (ожидания condvar можно отменить), либо вы могли бы использовать семафоры вместо мьютексы.
Изменить: Если вам действительно нужен способ завершения потоков, ожидающих мьютексов, вы можете заменить вызовы на pthread_mutex_lock
с вызовами вашей собственной функции, которая повторяет вызов pthread_mutex_timedlock
и проверка на флаг выхода на каждом тайм-ауте.