Вопрос по c – Обработка сигналов в C - прерывание в прерывании
Мне было интересно, можно ли прервать сигнал, когда моя программа обрабатывает другой сигнал одновременно, я попытался смоделировать его с помощью:
<code>#include<signal.h> #include<stdlib.h> #include<stdio.h> #include<unistd.h> #include<sys/wait.h> #include<string.h> void sig_output() { sigset_t set; sigprocmask(0,NULL,&set); printf("currently blocking:"); if (sigismember(&set,SIGUSR1)) printf("\nSIGUSR1"); if(sigismember(&set,SIGUSR2)) printf("\nSIGUSR2"); printf("\n"); return ; } void sig_handler(int sig) { raise(SIGUSR1); printf("start\n"); if (sig==SIGUSR1) printf("SIGUSR1\n"); else if (sig==SIGUSR2) printf("SIGUSR2\n"); printf("end\n"); return ; } void other_sig_handler(int sig) { printf("start - other\n"); if (sig==SIGUSR1) printf("SIGUSR1\n"); else if (sig==SIGUSR2) printf("SIGUSR2\n"); printf("end - other\n"); return ; } int main() { sig_output(); struct sigaction a; a.sa_handler=sig_handler; a.sa_flags=0; sigset_t set,old; //blocking SIGUSR1,SIGUSR2 sigemptyset(&set); sigaddset(&set,SIGUSR1); sigaddset(&set,SIGUSR2); printf("blocking SIGUSR1, SIGUSR2\n"); sigprocmask(SIG_SETMASK,&set,&old); sig_output(); //adding handles for SIGUSR1,SIGUSR2 sigemptyset(&(a.sa_mask)); sigaction(SIGUSR1,&a,NULL); a.sa_handler=other_sig_handler; sigaction(SIGUSR2,&a,NULL); printf("poczatek wysylania \n"); raise(SIGUSR1); raise(SIGUSR2); raise(SIGUSR1); printf("using sigsuspend\n"); sigsuspend(&old); printf("end of program\n"); return 0; } </code>
и каждый раз, когда я запускаю эту программу, я получаю
<code>currently blocking: blocking SIGUSR1, SIGUSR2 currently blocking: SIGUSR1 SIGUSR2 raising using sigsuspend start - other SIGUSR2 end - other start SIGUSR1 end end of program </code>
это всегда так?
sigaction(2)
manpage:
роцедуры @Signal обычно выполняются с сигналом, вызвавшим блокировку их вызова, но другие сигналы могут все же возникнуть. Глобальная маска сигналов определяет набор сигналов, в настоящее время заблокированных от доставки в процесс. Маска сигнала для процесса инициализируется от маски его родителя (обычно пустой). Может быть изменено с помощьюsigprocmask(2)
вызов или когда сигнал доставляется в процесс.
Вы можете контролировать, будет ли сигнал автоматически блокироваться в обработчике сигнала с помощьюSA_NODEFER
флаг.
sa_mask
вы поставляете наsigaction
это маска Дополнительная сигналы для блокировки, а не новая маска для установки. Так что если вы (1) попросите поймать сигнал X сsa_mask
, который явно блокирует сигнал Y (и неявно блокирует X, потому что вы оставляетеSA_NODEFER
off), затем (2) используйтеsigprocmask
, чтобы заблокировать сигнал Z, то (3) фактически поймает сигнал X, ваш обработчик работает с заблокированными всеми X, Y и Z.
torek
порядок доставки этих конкретных ожидающих сигналов не определен. Однако сигналыявляютс (в основном; есть исключение дляSIGCLD
, что традиционно делается путем «обмана») «без очереди», за исключением сигналов реального времени. Аспект без очереди означает, что если у вас есть сигнал X заблокирован, а затемraise
это дважды (как вы делали выше дляSIGUSR1
), вы получите его только один раз.
Единственный заказ, документированный по крайней мере в одной системе (MacOS):
If multiple signals are ready to be delivered at the same time, any signals that
could be caused by traps are delivered first.
(Это такие вещи, какSIGSEGV
а такжеSIGBUS
.) В общем, вы можете контролировать порядок доставки с помощью масок блокировки сигнала: разблокируйте любой конкретный сигнал (сигналы) в некоторой точке, и это те, которые могут быть доставлены в этой точке.
Если ты не поставилSA_NODEFER
, маска блокировки на входе в ваш обработчик всегда будет блокировать любой сигнал, который обрабатывает ваш обработчик, так что вам не придется беспокоиться о рекурсии.
Особый случай дляSIGCLD
происходит из System V, которая изначально реализовала это путем сброса обработчика наSIG_DFL
на каждогоSIGCLD
Доставка. (На самом деле, SysV сделал это со всеми сигналами, эффективно реализуяSA_RESETHAND
хочешь ты этого или нет.) Действие по умолчанию - сбросить сигнал, как если бы обработчик былSIG_IGN
. Это, конечно, создало условия гонки, когда несколько дочерних процессов закончили, прежде чем обработчик смог сделать свое дело. Однако вместо блочной / разблокированной модели люди из SysV взломали: в конце вашегоSIGCLD
Хендлер, ты бы позвонилsignal(SIGCLD, handler);
чтобы исправить обработчик. В этот момент, если бы были какие-то возбужденные дети, которые еще не былиwait
-ed для SysV немедленно сгенерирует Новый SIGCLD
, и ваш обработчик будет введен рекурсивно. Это выглядело так, как будто сигналы были поставлены в очередь, фактически не ставя их в очередь.
Подробнее о сигналах Linux см. (Например)http: //www.kernel.org/doc/man-pages/online/pages/man7/signal.7.htm.