Почему так сложно?Сигналы являются отдельными процессами (и, возможно, отдельными потоками в том же процессе, когда используются потоки POSIX), поэтому нет смысла использовать несколько процессов только для обработки сигналов.
Рассмотрим следующую программу:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
static const char *signal_name(const int signum)
{
switch (signum) {
case SIGUSR1: return "SIGUSR1";
case SIGUSR2: return "SIGUSR2";
case SIGALRM: return "SIGALRM";
case SIGSTOP: return "SIGSTOP";
case SIGINT: return "SIGINT";
default: return "unnamed";
}
}
int main(void)
{
siginfo_t info;
sigset_t mask;
int signum;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
sigaddset(&mask, SIGALRM);
sigaddset(&mask, SIGSTOP);
sigaddset(&mask, SIGINT);
/* Block the signals in mask. */
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
fprintf(stderr, "Cannot block signals: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("Process %d is ready for USR1 and USR2 signals.\n", (int)getpid());
fflush(stdout);
/* Ensure we receive a SIGALRM signal in five seconds or so. */
alarm(5);
while (1) {
/* Receive one of the signals in mask. */
signum = sigwaitinfo(&mask, &info);
if (signum == -1) {
const int err = errno;
/* EINTR should not happen, but if it did, it would be okay. */
if (err == EINTR)
continue;
fprintf(stderr, "sigwaitinfo() failed: %s (%d).\n", strerror(err), err);
exit(EXIT_FAILURE);
}
/* Describe the received signal. */
if (info.si_pid)
printf("Received %s (signal %d) from process %d.\n", signal_name(signum), signum, (int)info.si_pid);
else
printf("Received %s (signal %d).\n", signal_name(signum), signum);
fflush(stdout);
/* It is time to exit, if we receive INT or STOP, */
if (signum == SIGINT || signum == SIGSTOP)
break;
/* or an ALRM timeout; don't be fooled by kill()/sigqueue() SIGALRM. */
if (signum == SIGALRM && !info.si_pid)
break;
}
printf("Done.\n");
return EXIT_SUCCESS;
}
mask
содержит набор сигналов, заблокированных и полученных только через sigwaitinfo()
.alarm(5)
гарантирует, что сигнал SIGALRM будет доставлен примерно через пять секунд.Если установлено значение info.si_pid
, сигнал был отправлен с помощью kill()
(или аналогичных системных вызовов для ОС).
Эта программа просто описывает каждый принимаемый сигналдо тех пор, пока не сработает тайм-аут будильника или пока он не получит сигнал SIGSTOP или SIGINT.(Когда вы запускаете программу в терминале и нажимаете Ctrl + C , терминал отправляет сигнал SIGINT процессу (на переднем плане).)
Вы не можетеобмануть программу, отправив ей сигнал SIGALRM, потому что ядро устанавливает поле .si_pid
структуры siginfo_t
для процесса отправки;для всех «подлинных» сигналов тревоги он будет равен нулю.
Помните, что стандартные сигналы Unix / POSIX не ставятся в очередь и могут иметь задержку (например, спящие и таймеры могут доставляться позже, чем предполагалось).