Чи можна ігнорувати (втратити) сигнал?


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 signal(2)наголошує, що ви уникаєте цієї плутанини, використовуючи sigaction(2)натомість.
Нейт Елдредж

7

Ви не можете вірити, що кожен надісланий сигнал буде доставлений. Наприклад, ядро Linux "з’єднує" SIGCHLD, якщо процес займає тривалий час для обробки SIGCHLD із запущеного дочірнього процесу.

Щоб відповісти на іншу частину вашого запитання, сигнали потрапляють "у чергу" всередині ядра, якщо кількість різних сигналів надходить за занадто короткий інтервал.

Ви повинні використовувати sigaction()для налаштування обробника сигналу з sa_sigactionчленом siginfo_t, ретельно встановлюючи sa_maskчлен siginfo_tаргументу. Я думаю, що це означає принаймні замаскувати всі сигнали про "асинхрон". Згідно з довідковою сторінкою для 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.