выполнение обработчика сигнала не выгружается в Linux? - PullRequest
6 голосов
/ 25 мая 2011

У меня есть процесс p, зарегистрированный обработчиком сигнала для SIGALRM. Таймер настроен на периодическую отправку сигнала SIGALRM для обработки p. Есть также несколько потоков, работающих в процессе p. Является ли обработчик сигнала, когда он запускается и выполняется, невыполнимым? Или сказать, что выполнение обработчика сигнала не будет прервано ни одним потоком в процессе p?

PS: я думал, что обработчик сигнала выполняется в ядре (не так ли?), И ядро ​​непривлекательно для потоков пользовательского режима? Поправь меня, если это не так ...

Ответы [ 3 ]

17 голосов
/ 25 мая 2011

В значительной степени - не - работа с общими данными в обработчике сигналов почти всегда приводит к боли, работе с потоками, и вы попадаете в беспорядок.

По умолчанию сигнал блокируется во время работы обработчика сигнала (по крайней мере, в Linux, что может быть не всегда верно), поэтому, по крайней мере, обработчик сигнала не будет прерван сам по себе.Хотя, если у вас есть несколько потоков, и сигнал не блокируется в других потоках, обработчик сигнала вполне может быть запущен одновременно в нескольких потоках.

Один поток получит сигнал и выполнит обработчик, этоболее или менее случайный, какой поток это будет, хотя вы можете контролировать его, блокируя сигнал во всех потоках, которые вы не хотите обрабатывать сигнал.

Однако любой из других потоков, в котором обрабатывается сигнал, может работать параллельно.Поток, обрабатывающий сигнал, может запустить обработчик сигнала практически в любой точке программы (если сигнал не заблокирован). Поэтому для защиты этих данных вам понадобится какая-то блокировка.Проблема в том, что вы не можете использовать ни один из нормальных примитивов блокировки потоков, они не безопасны для асинхронного сигнала.Это означает, что если вы, например, пытаетесь получить pthread_mutex_t в обработчике сигналов, вы легко блокируете вашу программу.

Единственные функции, которые вы можете безопасно вызывать в обработчике сигналов, - это перечисленные здесь .Что касается защиты общих данных, вы можете использовать sigblock () / sigunblock () как своего рода защиту, гарантирующую, что обработчик сигнала не будет работать, пока вы получаете доступ к этим общим данным - и сигнал должен быть заблокирован во всехпотоки, в противном случае он будет работать только в одном из потоков, у которого он не заблокирован - идти по этому пути - безумие.

Практически единственные общие данные, к которым вы можете безопасно обращаться в обработчике сигналов, этоsig_atomic_t типа, на практике обычно безопасны и другие типы примитивов.

То, что вы действительно должны делать в обработчике сигналов, это просто

  • установить глобальный флаг
  • проверяйте этот флаг в другом месте кода, когда это необходимо, и предпринимайте действия

или

  • имеют какой-то основной цикл, который отслеживает файловые дескрипторы для событий, используя select () /poll () или аналогичный.
  • создайте канал и следите за тем, чтобы в вашем основном цикле
  • write () байт в канал обрабатывали в вашем обработчике сигналов
  • , запустите ваш код длядевместе с сигналом, включая защиту любых общих данных, когда основной цикл обнаруживает событие в этом канале

или

  • Держите запасной поток вокруг блока
  • у данного сигнала во всех ваших потоках
  • есть этот резервный цикл при вызове sigsuspend () с маской сигнала, обеспечивающей доставку этого сигнала.
  • запустите ваш код, включая защиту любых общих данных для обработкис сигналом, когда sigsuspend () возвращает
5 голосов
/ 26 мая 2011

Является ли обработчик сигнала, когда срабатывает и выполняется, ун-прерываться?

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

Я думал, что обработчик сигнала выполнен в ядре (не так ли)

Нет, обработчик сигнала не выполняется в режиме ядра.

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

2 голосов
/ 25 мая 2011

Краткий ответ - «нет».

Читайте sigaction , особенно поле sa_mask.По умолчанию ваш поток может быть прерван другим сигналом, даже если он находится в обработчике сигнала.

Кроме того, фраза «прервана любым потоком в процессе p» не имеет смысла.В общем случае потоки запускаются одновременно;они не «перебивают» друг друга (за исключением вызова pthread_kill ()).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...