Основы программирования в Linux
Если вы хотите сохранить обработчик сигнала и продолжать реагировать на комбинацию клавиш <Ctrl>+<C>, вам придется восстановить его, вызвав функцию
еще раз. Это приведет к возникновению короткого промежутка времени, начиная с запуска функции прерывания и до момента восстановления обработчика сигнала, в течение которого сигнал не будет обрабатываться. Если второй сигнал будет получен в этот период, вопреки вашим желаниям программа может завершиться.signalПримечаниеМы не рекомендуем вам пользоваться функцией
для перехвата сигналов. Мы включили ее в книгу, потому что она будет часто встречаться в более старых программах. Позже вы увидитеsignal, более четко определенный и надежный интерфейс, который следует применять в новых программах.sigactionФункция
возвращает предыдущее значение обработчика для заданного типа сигнала, если таковой есть, или в противном случаеsignalс установкой положительного значения в переменнойSIG_ERR. Если задан неверный сигнал или делается попытка обработать сигнал, который не может быть перехвачен или игнорироваться, напримерerrno, переменнойSIGKILLприсваивается значениеerrno.EINVALОтправка сигналов
Процесс может отправить сигнал другому процессу, включая себя самого, с помощью вызова функции
. Вызов завершится аварийно, если у программы нет полномочий на отправку сигнала, часто потому что процесс-получатель принадлежит другому пользователю. Эта функция эквивалентна команде оболочки с тем же именем.kill<b>#include <sys/types.h></b><b>#include <signal.h></b><b>int kill(pid_t pid, int sig);</b>Функция
посылает заданный сигналkillпроцессу с идентификатором, заданным в аргументеsig. В случае успеха она возвращает 0. Для отправки сигнала посылающий процесс должен иметь право на выполнение этого действия. Обычно это означает, что у обоих процессов должен быть один и тот же идентификатор пользователя ID (т.е. вы можете отправить сигнал только одному из собственных процессов, хотя суперпользователь может отправлять сигналы любому процессу).pidФункция
завершится аварийно, вернет -1 и установит значение переменнойkill, если задан неверный сигнал, (errnoравнаerrno), у процесса нет полномочий (EINVAL) или заданный процесс не существует (EPERM).ESRCHСигналы предоставляют полезное средство, именуемое будильником или сигналом тревоги. Вызов функции
может применяться для формирования сигналаalarmв определенное время в будущем.SIGALRM<b>#include <unistd.h></b><b>unsigned int alarm(unsigned int seconds);</b>Вызов
намечает доставку сигналаalarmчерезSIGALRMсекунд. В действительности сигнал будильника будет доставлен чуть позже из-за обработки задержек и учета неопределенностей. Значение 0 отменяет любой невыполненный запрос на сигнал будильника. Вызов функцииsecondsдо получения сигнала может вызвать сброс графика доставки. У каждого процесса может быть только один невыполненный сигнал будильника. Функцияalarmвозвращает количество секунд, оставшихся до отправки любого невыполненного вызова,alarm, или -1 в случае аварийного завершения.alarmДля того чтобы увидеть как работает функция
, можно сымитировать ее действие, используя вызовыalarm,forkиsleep(упражнение 11.8). Программа сможет запустить новый процесс с единственной целью — отправить сигнал спустя какое- то время.signalУпражнение 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в свой родительский процесс:SIGALRMint 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);}Когда вы выполните программу, то увидите, что она делает паузу на пять секунд, в течение которых ждет имитации будильника: