К сожалению, именно такая модель сигналов используется в ANSI/ISO-стандарте С [55] Вообще-то, не совсем так. Модель обработки сигналов ANSI/ISO С специфицирована немного иначе, чем мы ее представили. Однако она допускает сброс обработчика в значение SIG_DFL перед доставкой сигнала, что делает функции signal() в ASNI/ISO С ненадежными.
. Хотя программные интерфейсы надежных сигналов, в которых исправлен этот недостаток, уже широко распространены, стандартизация ненадежных сигналов в ANSI/ISO, видимо, останется навсегда.
Реализация BSD для решения проблемы множества сигналов полагается на простое ожидание завершения работы каждого обработчика сигналов в процессе перед доставкой следующего. Это гарантирует то, что каждый сигнал будет рано или поздно обработан, а также исключает риск переполнения стека. Вспомним, что когда ядро удерживает сигнал для отложенной доставки, сигнал называется ожидающим(pending).
Однако если процессу отправлен сигнал SIG ЧТО-ТО
, в то время, как SIG ЧТО
-ТО уже находится в состоянии ожидания, то в этом случае процессу доставляется только первый из них. У процесса нет никакой возможности узнать, сколько раз один и тот же сигнал был отправлен ему, поскольку множество одинаковых сигналов подряд воспринимаются как один. Обычно это не представляет собой проблему. Поскольку сигнал не несет в себе никакой информации помимо собственно номера сигнала, двойная посылка сигнала за очень короткий отрезок времени может быть воспринята как одиночная, потому если программа примет сигнал только однажды, это не имеет особого значения. Это отличается от варианта с обработкой второго сигнала по умолчанию (что делается при ненадежной схеме обработки сигналов) [56] Спецификация POSIX Real Time Signal позволяет некоторые сигналам ставить в очередь, и для сигналов, работающих с ограниченными объемами данных, существенно изменяет эту модель. Сигналы реального времени обсуждаются ближе к концу этой главы.
.
Идея об автоматической блокировкесигналов была расширена для того, чтобы позволить процессам блокировать сигналы явным образом. Это облегчает защиту критичных участков кода, в то же время гарантируя обработку всех отправленных сигналов. Такая защита позволяет обработчикам сигналов манипулировать структурами данных, которые поддерживаются другими участками кода, за счет простой синхронизации.
Хотя BSD представляет адаптированную версию модели сигналов POSIX, комитет по стандартизации POSIX упростил ее для системных вызовов, с тем чтобы модифицировать диспозицию групп сигналов, предлагая новые системные вызовы для оперирования наборами сигналов. Наборы сигналов представлены типом данных sigset_t
, и для манипулирования ими предусмотрен набор макросов [57] Это аналогично типу fd_set , который используется системным вызовом select() , описанным в главе 13.
.
12.1.4. Сигналы и системные вызовы
Часто сигналы доставляются процессу, который находится состоянии ожидания наступления некоторого внешнего события. Например, текстовый редактор часто ожидает завершения read()
, чтобы возвратить ввод терминала. Когда системный администратор посылает процессу сигнал SIGTERM
(нормальный сигнал, посылаемый командой kill
, позволяющий процессу завершиться чисто), то процесс может обработать его, как описано ниже.
1. Не пытаться перехватить сигнал и быть прерванным ядром (обработка SIGTERM
по умолчанию). Это оставляет пользовательский терминал в нестандартной конфигурации, затрудняя ему продолжение работы.
2. Перехватить сигнал, очистить терминал с помощью обработчика этого сигнала, затем выйти. Хотя это кажется привлекательным, в сложных программах трудно написать такой обработчик, который знал бы достаточно о том, что делает программа в момент прерывания, чтобы правильно выполнить очистку.
3. Перехватить сигнал, установить флаг, обозначающий, что сигнал получен, и каким-то образом обеспечить выход из блокирующего системного вызова (в данном случае read()
) с индикацией ошибки — в знак того, что произошло что-то необычное. Нормальный порядок выполнения затем должен проверить флаг и обработать его соответствующим образом.
Поскольку последний вариант выглядит намного чище и легче остальных, оригинальная реализация сигналов заставляет медленные системные вызовывозвратить EINTR
, когда они прерываются сигналом, в то время как быстрые системные вызовызавершаются перед тем, как сигнал будет доставлен.
Читать дальше