Шрифт:
Функция
kill
завершится аварийно, вернет -1 и установит значение переменной errno
, если задан неверный сигнал, (errno
равна EINVAL
), у процесса нет полномочий (EPERM
) или заданный процесс не существует (ESRCH
). Сигналы предоставляют полезное средство, именуемое будильником или сигналом тревоги. Вызов функции
alarm
может применяться для формирования сигнала SIGALRM
в определенное время в будущем.
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
Вызов
alarm
намечает доставку сигнала SIGALRM
через seconds
секунд. В действительности сигнал будильника будет доставлен чуть позже из-за обработки задержек и учета неопределенностей. Значение 0 отменяет любой невыполненный запрос на сигнал будильника. Вызов функции alarm
до получения сигнала может вызвать сброс графика доставки. У каждого процесса может быть только один невыполненный сигнал будильника. Функция alarm
возвращает количество секунд, оставшихся до отправки любого невыполненного вызова, alarm
, или -1 в случае аварийного завершения. Для того чтобы увидеть как работает функция
alarm
, можно сымитировать ее действие, используя вызовы fork
, sleep
и signal
(упражнение 11.8). Программа сможет запустить новый процесс с единственной целью — отправить сигнал спустя какое- то время. Упражнение 11.8 Будильник
В программе alarm.c первая функция,
ding
, имитирует будильник.
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
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 <unistd.h>
int pause(void);
Функция возвращает -1 (если следующий полученный сигнал не вызвал завершения программы) с переменной
errno
, равной EINTR
, в случае прерывания сигналом. Лучше для ожидания сигналов применять функцию sigsuspend
, которую мы обсудим чуть позже в этой главе. Как это работает
Программа имитации будильника запускает новый процесс вызовом
fork
. Этот дочерний процесс ожидает пять секунд и затем посылает сигнал SIGALRM
своему родителю. Родитель подготавливается к получению сигнала SIGALRM
и затем делает паузу до тех пор, пока не будет получен сигнал. Функция printf
не вызывается непосредственно в обработчике, вместо этого вы устанавливаете флаг, который проверяете позже.