Чтение онлайн

на главную - закладки

Жанры

Основы программирования в Linux
Шрифт:

Функция

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
не вызывается непосредственно в обработчике, вместо этого вы устанавливаете флаг, который проверяете позже.

Применение сигналов и приостановка выполнения — важные составляющие программирования в ОС Linux. Это означает, что программа необязательно должна выполняться все время. Вместо того чтобы долго работать в цикле, проверяя, не произошло ли событие, она может ждать его наступления. Это особенно важно в многопользовательской среде, где процессы совместно используют один процессор, и такой вид деятельного ожидания оказывает большое влияние на производительность системы. Особая проблема, связанная с сигналами, заключается в том, что вы никогда не знаете наверняка, что произойдет, если сигнал появится в середине системного вызова? (Ответ весьма неудовлетворительный: все зависит от ситуации.) Вообще следует беспокоиться только о "медленных" системных вызовах, таких как считывание с терминала, когда системный вызов может вернуться с ошибкой, если сигнал появится во время его пребывания в режиме ожидания. Если вы начнете применять сигналы в своих программах, нужно учитывать, что некоторые системные вызовы могут закончиться аварийно, если сигнал создаст ошибочную ситуацию, которую вы могли не принимать во внимание до того, как добавили обработку сигналов.

Нужно тщательно программировать сигналы, потому что существует ряд "состояний гонок", возникающих в программах, применяющих сигналы. Например, если вы намерены вызвать pause для ожидания сигнала и этот сигнал возникнет до вызова pause, ваша программа может ждать неопределенно долго события, которое не произойдет. Новоиспеченный программист сталкивается с множеством таких состояний гонок, важных проблем синхронизации или согласования времени. Всегда очень внимательно проверяйте программный код, использующий сигналы.

Поделиться:
Популярные книги

Черный Маг Императора 7 (CИ)

Герда Александр
7. Черный маг императора
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Черный Маг Императора 7 (CИ)

Кукловод

Злобин Михаил
2. О чем молчат могилы
Фантастика:
боевая фантастика
8.50
рейтинг книги
Кукловод

Последний Паладин. Том 6

Саваровский Роман
6. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 6

Вечный. Книга VII

Рокотов Алексей
7. Вечный
Фантастика:
боевая фантастика
рпг
попаданцы
5.00
рейтинг книги
Вечный. Книга VII

Личный аптекарь императора. Том 4

Карелин Сергей Витальевич
4. Личный аптекарь императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Личный аптекарь императора. Том 4

Афганский рубеж 4

Дорин Михаил
4. Рубеж
Фантастика:
попаданцы
альтернативная история
6.00
рейтинг книги
Афганский рубеж 4

Бестужев. Служба Государевой Безопасности

Измайлов Сергей
1. Граф Бестужев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности

Сильнейший Столп Империи. Книга 1

Ермоленков Алексей
1. Сильнейший Столп Империи
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Сильнейший Столп Империи. Книга 1

Снайпер

Поселягин Владимир Геннадьевич
3. Жнец
Фантастика:
боевая фантастика
попаданцы
5.60
рейтинг книги
Снайпер

Отмороженный 13.0

Гарцевич Евгений Александрович
13. Отмороженный
Фантастика:
боевая фантастика
попаданцы
рпг
фантастика: прочее
фэнтези
5.00
рейтинг книги
Отмороженный 13.0

Ермак. Телохранитель

Валериев Игорь
2. Ермак
Фантастика:
альтернативная история
7.50
рейтинг книги
Ермак. Телохранитель

Мятежник

Прокофьев Роман Юрьевич
4. Стеллар
Фантастика:
боевая фантастика
7.39
рейтинг книги
Мятежник

Хозяин Стужи 4

Петров Максим Николаевич
4. Злой Лед
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Хозяин Стужи 4

Путь

Yagger Егор
Фантастика:
космическая фантастика
4.25
рейтинг книги
Путь