В значительной степени - не - работа с общими данными в обработчике сигналов почти всегда приводит к боли, работе с потоками, и вы попадаете в беспорядок.
По умолчанию сигнал блокируется во время работы обработчика сигнала (по крайней мере, в Linux, что может быть не всегда верно), поэтому, по крайней мере, обработчик сигнала не будет прерван сам по себе.Хотя, если у вас есть несколько потоков, и сигнал не блокируется в других потоках, обработчик сигнала вполне может быть запущен одновременно в нескольких потоках.
Один поток получит сигнал и выполнит обработчик, этоболее или менее случайный, какой поток это будет, хотя вы можете контролировать его, блокируя сигнал во всех потоках, которые вы не хотите обрабатывать сигнал.
Однако любой из других потоков, в котором обрабатывается сигнал, может работать параллельно.Поток, обрабатывающий сигнал, может запустить обработчик сигнала практически в любой точке программы (если сигнал не заблокирован). Поэтому для защиты этих данных вам понадобится какая-то блокировка.Проблема в том, что вы не можете использовать ни один из нормальных примитивов блокировки потоков, они не безопасны для асинхронного сигнала.Это означает, что если вы, например, пытаетесь получить pthread_mutex_t в обработчике сигналов, вы легко блокируете вашу программу.
Единственные функции, которые вы можете безопасно вызывать в обработчике сигналов, - это перечисленные здесь .Что касается защиты общих данных, вы можете использовать sigblock () / sigunblock () как своего рода защиту, гарантирующую, что обработчик сигнала не будет работать, пока вы получаете доступ к этим общим данным - и сигнал должен быть заблокирован во всехпотоки, в противном случае он будет работать только в одном из потоков, у которого он не заблокирован - идти по этому пути - безумие.
Практически единственные общие данные, к которым вы можете безопасно обращаться в обработчике сигналов, этоsig_atomic_t
типа, на практике обычно безопасны и другие типы примитивов.
То, что вы действительно должны делать в обработчике сигналов, это просто
- установить глобальный флаг
- проверяйте этот флаг в другом месте кода, когда это необходимо, и предпринимайте действия
или
- имеют какой-то основной цикл, который отслеживает файловые дескрипторы для событий, используя select () /poll () или аналогичный.
- создайте канал и следите за тем, чтобы в вашем основном цикле
- write () байт в канал обрабатывали в вашем обработчике сигналов
- , запустите ваш код длядевместе с сигналом, включая защиту любых общих данных, когда основной цикл обнаруживает событие в этом канале
или
- Держите запасной поток вокруг блока
- у данного сигнала во всех ваших потоках
- есть этот резервный цикл при вызове sigsuspend () с маской сигнала, обеспечивающей доставку этого сигнала.
- запустите ваш код, включая защиту любых общих данных для обработкис сигналом, когда sigsuspend () возвращает