Сигналы предоставляют полезное средство, именуемое будильником или сигналом тревоги. Вызов функции alarm может применяться для формирования сигнала SIGALRM в определенное время в будущем.
#include
unsigned int alarm(unsigned int seconds);
Вызов alarm намечает доставку сигнала SIGALRM через seconds секунд. В действительности сигнал будильника будет доставлен чуть позже из-за обработки задержек и учета неопределенностей. Значение 0 отменяет любой невыполненный запрос на сигнал будильника. Вызов функции alarm до получения сигнала может вызвать сброс графика доставки. У каждого процесса может быть только один невыполненный сигнал будильника. Функция alarm возвращает количество секунд, оставшихся до отправки любого невыполненного вызова, alarm, или -1 в случае аварийного завершения.
Для того чтобы увидеть как работает функция alarm, можно сымитировать ее действие, используя вызовы fork, sleep и signal (упражнение 11.8). Программа сможет запустить новый процесс с единственной целью — отправить сигнал спустя какое- то время.
В программе alarm.c первая функция, ding, имитирует будильник.
#include
#include
#include
#include
#include
static int alarm_fired = 0;
void ding(int sig) {
alarm_fired = 1;
}
В функции main вы заставляете дочерний процесс ждать пять секунд перед отправкой сигнала SIGALRM в свой родительский процесс:
int main() {
pid_t pid;
printf("alarm application starting\n");
pid = fork();
switch(pid) {
case -1:
/* Аварийное завершение */
perror("fork failed");
exit(1);
case 0:
/* Дочерний процесс */
sleep(5);
kill(getppid(), SIGALRM);
exit(0);
}
Родительский процесс устроен так, что перехватывает сигнал SIGALRM с помощью вызова signal и затем ждет неизбежности:
/* Если мы оказались здесь, то мы — родительский процесс */
printf("waiting for alarm to go off\n");
(void)signal(SIGALRM, ding);
pause();
if (alarm_fired) printf("Ding!\n");
printf("done\n");
exit(0);
}
Когда вы выполните программу, то увидите, что она делает паузу на пять секунд, в течение которых ждет имитации будильника:
$ ./alarm
alarm application starting
waiting for alarm to go off
<5 second pause>
Ding!
done $
В этой программе вводится новая функция pause, которая просто приостанавливает выполнение программы до появления сигнала. Когда она получит сигнал, выполняется любой установленный обработчик, и выполнение продолжается как обычно. Она объявляется следующим образом:
#include
int pause(void);
Функция возвращает -1 (если следующий полученный сигнал не вызвал завершения программы) с переменной errno, равной EINTR, в случае прерывания сигналом. Лучше для ожидания сигналов применять функцию sigsuspend, которую мы обсудим чуть позже в этой главе.
Как это работает
Программа имитации будильника запускает новый процесс вызовом fork. Этот дочерний процесс ожидает пять секунд и затем посылает сигнал SIGALRM своему родителю. Родитель подготавливается к получению сигнала SIGALRM и затем делает паузу до тех пор, пока не будет получен сигнал. Функция printf не вызывается непосредственно в обработчике, вместо этого вы устанавливаете флаг, который проверяете позже.