Сигналы играют важную роль в различных частях API системных вызовов, и мы еще вернемся к ним в последующих главах. Кроме того, некоторые функции, связанные с сигналами, также характерны для потоков (например, pthread_kill() и pthread_sigmask()), но мы отложим обсуждение этих функций до раздела 33.2.

Дополнительная информация

См. ресурсы, перечисленные в разделе 20.15.

22.15. Упражнения

22.1. В разделе 22.2 отмечалось, что если остановленный процесс, установивший обработчик для заблокированного сигнала SIGCONT, в дальнейшем возобновляется в результате получения сигнала SIGCONT, то обработчик активируется только после разблокирования сигнала SIGCONT. Напишите программу, демонстрирующую это поведение. Не забудьте, что процесс может быть остановлен путем ввода в терминал символа приостановки (обычно Ctrl+Z), а сигнал SIGCONT может быть отправлен в процесс с помощью команды kill — CONT (или неявно, с помощью команды оболочки fg).

22.2. Если сигнал реального времени и стандартный сигнал ожидают процесс, стандарт SUSv3 не устанавливает, который из сигналов должен быть доставлен первым. Напишите программу, демонстрирующую, что делает Linux в этом случае. (С помощью программы установите обработчик для всех сигналов, заблокируйте сигналы на определенное время, чтобы вы могли отправить в программу несколько сигналов, а затем разблокируйте все сигналы.)

22.3. В разделе 22.10 сказано, что прием сигналов с помощью функции sigwaitinfo() осуществляется быстрее по сравнению с использованием обработчика сигнала с функцией sigsuspend(). В программе signals/sig_speed_sigsuspend.c, поставляемой с исходным кодом для этой книги, задействуется функция sigsuspend() для реализации обмена сигналами между родительским и дочерним процессами. Засеките время выполнения этой программы при обмене одним миллионом сигналов между двумя процессами. (Количество сигналов, которыми необходимо обменяться, указывается в аргументе командной строки программы.) Создайте модифицированную версию программы, в которой будет использоваться функция sigwaitinfo(), и засеките время выполнения этой версии программы. Какова разница в скоростях выполнения этих программ?

<p>23. Таймеры и переход в режим сна</p>

Таймер позволяет процессу планировать появление уведомлений, которые должны поступать в будущем. Переход в режим сна дает возможность процессу (или потоку) приостанавливать выполнение на определенный период времени. В данной главе описываются интерфейсы для этих механизмов. Мы рассмотрим следующие темы:

• классические программные интерфейсы UNIX для установки интервальных таймеров (setitimer() и alarm()), срабатывание которых приводит к уведомлению процесса;

• программные интерфейсы, которые позволяют процессу приостанавливать выполнение на определенном отрезке времени;

• программные интерфейсы системных часов и таймеров, входящие в стандарт POSIX.1b;

• механизм timerfd, доступный только в Linux, который позволяет создавать таймеры, чье срабатывание можно определить по файловому дескриптору.

23.1. Интервальные таймеры

Системный вызов setitimer() устанавливает интервальный таймер, который срабатывает в какой-то момент времени (возможно, многократно и с определенным интервалом).

#include

int setitimer(int which, const struct itimerval *new_value,

struct itimerval *old_value);

Возвращает 0 при успешном завершении или –1, если случилась ошибка

С помощью вызова setitimer() процесс может устанавливать таймеры трех разных видов, в зависимости от выбранного значения which:

• ITIMER_REAL — создает таймер, который ведет обратный отсчет в реальном времени (то есть так, как на обычных настенных часах). По истечении времени процессу передается сигнал SIGALRM;

• ITIMER_VIRTUAL — создает таймер, который ведет обратный отсчет в виртуальном времени процесса (то есть учитывается процессорное время в пользовательском режиме). По истечении времени процессу передается сигнал SIGVTALRM;

• ITIMER_PROF — создает профилирующий таймер, который ведет обратный отсчет с учетом времени процесса (суммируя процессорное время в пользовательском режиме и в режиме ядра). По истечении времени процессу передается сигнал SIGPROF.

Стандартное действие всех сигналов, которые генерируются таймерами, состоит в завершении процесса. Если нам нужно сделать что-то другое, мы должны установить собственный обработчик сигнала.

Аргументы new_value и old_value представляют собой указатели на структуры itimerval, определенные следующим образом:

struct itimerval {

struct timeval it_interval; /* Временной отрезок для интервального таймера */

struct timeval it_value; /* Текущее значение (время

до следующего срабатывания) */

};

Каждое из полей структуры itimerval является, в свою очередь, структурой типа timeval, содержащей секунды и микросекунды:

struct timeval {

time_t tv_sec; /* Секунды */

suseconds_t tv_usec; /* Микросекунды (long int) */

};

Перейти на страницу:

Похожие книги