Может ли сигнал быть проигнорирован (потерян)?

9

У меня есть приложение, которое связывается с рабочими через сигналы (в частности, SIGUSR1 / SIGUSR2 / SIGSTOP).

Могу ли я верить, что что бы ни случилось, каждый сигнал будет доставлен и обработан обработчиком?

Что произойдет, если сигналы будут отправлены быстрее, чем невозможно для приложения, чтобы обработать их (например, из-за высокой нагрузки на хост в данный момент)?

КАП
источник

Ответы:

8

Помимо проблемы «слишком много сигналов», сигналы могут быть явно проигнорированы. От man 2 signal:

If the signal signum is delivered to the process, then one of the
following happens:    
  *  If the disposition is set to SIG_IGN, then the signal is ignored.

Сигналы также могут быть заблокированы. От man 7 signal;

A signal may be blocked, which means that it will not be delivered
until it is later unblocked.  Between the time when it is generated
and when it is delivered a signal is said to be pending.

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

Что происходит, когда несколько сигналов доставляются до того, как процесс завершит обработку предыдущих? Это зависит от ОС. signal(2)Страница руководства связана выше рассуждает по поводу его:

  • Система V сбросит расположение сигнала на значение по умолчанию. Хуже того, быстрая доставка нескольких сигналов приведет к рекурсивным (?) Вызовам.
  • BSD автоматически блокирует сигнал, пока не будет завершен обработчик.
  • В Linux это зависит от флагов компиляции, установленных для GNU libc, но я ожидаю, что поведение BSD.
Мур
источник
4
Справочная страница Linux для Linux signal(2)настоятельно рекомендует вам избегать этой путаницы, используя sigaction(2)вместо этого.
Нейт Элдредж
7

Вы не можете поверить, что каждый отправленный сигнал будет доставлен. Например, ядро Linux «объединяет» SIGCHLD, если процессу требуется много времени для обработки SIGCHLD из вышедшего дочернего процесса.

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

Вы должны использовать sigaction()для настройки обработчика сигнала с sa_sigactionчленом siginfo_t, тщательно настраивая sa_maskчлен siginfo_tаргумента. Я думаю, что это означает, по крайней мере, маскирование всех «асинхронных» сигналов. Согласно man-странице для Linux sigaction(), вы также замаскируете обрабатываемый сигнал. Я думаю, что вы должны установить sa_flagsчлен SA_SIGINFO, но я не могу вспомнить, почему у меня есть это суеверие. Я полагаю, что это сделает ваш процесс обработчиком сигналов, который остается установленным без условий гонки, и тот, который не прерывается большинством других сигналов.

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

Кроме того, вы захотите очень тщательно протестировать код обработки сигналов. Проведите небольшой тестовый процесс и отправьте как можно больше сигналов SIGUSR1 и SIGUSR2, возможно, из 2 или 3 специальных программ для отправки сигналов. Смешайте и некоторые другие сигналы, после того как вы уверены, что ваш код может обрабатывать SIGUSR1 и SIGUSR2 быстро и правильно. Приготовьтесь к трудной отладке.

Если вы используете Linux и только Linux, вы можете подумать о том, signalfd()чтобы создать дескриптор файла, который вы можете использовать, select()или опросить для получения этих сигналов. Использование signalfd()может облегчить отладку.

Брюс Эдигер
источник
2
Это не просто SIGCLD, который объединяется: все сигналы потенциально объединяются, если они доставляются до того, как они могут быть обработаны.
Жиль "ТАК ... перестать быть злым"
Есть ли мера того, как долго "слишком долго" для сигналов SIGCHLD? Я испытываю такое поведение в моей программе прямо сейчас, и мой обработчик сигнала не занимает больше ~ 100 мс, на что я рассчитывал.
xrisk
@Rishav - насколько мне известно, нет никакого способа узнать, что такое «слишком долго». Я ожидаю, что общая нагрузка на систему важна. То есть то, что делают другие процессы и ядро, будет влиять на «как долго» между сигналами, чтобы они объединились. Думаю, это не очень полезный ответ.
Брюс Эдигер
6

Сигнал гарантированно доставляется в том смысле, что если процесс успешно вызывает kill, тогда цель получит сигнал. Это асинхронно: отправитель не может узнать, когда сигнал получен или обработан. Однако это не гарантирует, что сигнал будет доставлен. Цель может умереть, прежде чем сможет обработать сигнал. Если цель игнорирует сигнал во время его доставки, сигнал не будет иметь никакого эффекта. Если цель получает несколько экземпляров одного и того же номера сигнала, прежде чем она сможет их обработать, сигналы могут (и обычно) объединяются: если вы отправляете один и тот же сигнал дважды процессу, вы не можете знать, получит ли процесс сигнал один или два раза Сигналы в основном предназначены для уничтожения процесса или как способ заставить процесс обратить внимание, они не предназначены для связи как таковой.

Если вам нужна надежная доставка, вам нужен другой механизм коммуникации. Существует два основных механизма связи между процессами: канал обеспечивает однонаправленную связь; сокет позволяет двунаправленную связь и несколько соединений к одному серверу. Если вам нужно, чтобы цель обрабатывала столько уведомлений, сколько отправляете, отправляйте байты по каналу.

Жиль "ТАК - перестань быть злым"
источник
4
Вы хотели написать «Сигнал гарантированно будет доставлен», поскольку вы продолжили описывать некоторые способы, по которым сигнал не будет доставлен (т.е. процесс прервался до того, как он был получен, или сигналы были объединены)?
Джонни
2

Ядро может объединять стандартные сигналы, если более одного доставлено во время блокировки. С другой стороны, сигналы в реальном времени не имеют аналогичных ограничений.

Из справочной страницы сигнала (7) :

Сигналы в реальном времени отличаются следующим:

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

Попробуйте использовать сигнал с номером в диапазоне от SIGRTMIN до SIGRTMAX.

Грэм Раштон
источник
Существует ограничение для сигналов в реальном времени, но оно довольно высокое. Сигнал будет сброшен, если количество ожидающих сигналов, отправленных пользователем, превысит RLIMIT_SIGPENDING. ulimit -iпоказывает это значение как 63432 на Ubuntu 18.04.
Bain