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

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

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

ITIMER_REAL Отслеживает время в терминах настенных часов — в реальном времени (в зависимости от выполнения процесса) — и генерирует сигнал SIGALRM. Несовместим с системным вызовом alarm(), который используется функцией sleep(). Не применяйте ни alarm(), ни sleep(), если имеется реальный интервальный таймер. ITIMER_VIRTUAL Подсчитывает время только при исполнении процесса — не учитывая системные вызовы, которые производит процесс — и генерирует сигнал SIGVTALRM. ITIMER_PROF Подсчитывает время только при выполнении процесса — включая время, за которое ядро посылает исполнительные системные вызовы от имени процесса, и не включая время, потраченное на прерывание процесса по инициативе самого процесса — и генерирует сигнал SIGPROF. Учет времени, затраченного на обработку прерываний, оказывается настолько трудоемким, что даже может изменить настройки таймера.

Комбинация таймеров ITIMER_VIRTUAL и ITIMER_PROF часто используется в профилирующих кодах.

Каждый из этих таймеров генерирует ассоциированный сигнал об истечении таймера в пределах одного хода системных часов (как правило, 1-10 миллисекунд). Если процесс работает в данное время, то сигнал генерируется сразу же; в противном случае сигнал генерируется немного позже (в зависимости от загрузки системы). Поскольку таймер ITIMER_VIRTUAL следит за временем только во время работы процесса, то сигнал всегда доставляется незамедлительно.

Используйте структуру struct itimerval для передачи запроса и установки интервальных таймеров.

struct itimerval {

 struct timeval it_interval;

 struct timeval it_value;

};

Член it_value показывает количество времени, оставшееся до отправления следующего сигнала. Член it_interval определяет время между сигналами; каждый раз при истечении таймера это значение присваивается переменной it_value.

Для взаимодействия с интервальными таймерами предусмотрены два системных вызова. Оба принимают аргумент which, указывающий обрабатываемый таймер.

int getitimer(int which, struct itimerval *val);

Переменной val присваивается текущее состояние таймера which.

int setitimer(int which, struct itimerval *new, struct itimerval *old);

Устанавливает таймер which на значение new и заменяет old предыдущей установкой, если она не равна NULL.

Если параметр таймера it_value приравнять к нулю, он немедленно заблокируется. Ввод нулевого значения для it_interval отключает таймер после следующего запуска.

В следующем примере родительский процесс активизирует дочерний процесс, запускает односекундный таймер ITIMER_REAL, засыпает на 10 секунд, а затем уничтожает дочерний процесс.

 1: /* itimer.c */

 2:

 3: #include <stdio.h>

 4: #include <stdlib.h>

 5: #include <sys/wait.h>

 6: #include <unistd.h>

 7: #include <string.h>

 8: #include <signal.h>

 9: #include <sys/time.h>

10:

11:

12: void catch_signal(int ignored) {

13:  static int iteration=0;

14:

15:  printf("получен сигнал интервального таймера, итерация %d ",

16:   iteration++);

17: }

18:

19: pid_t start_timer(int interval) {

20:  pid_t child;

21:  struct itimerval it;

22:  struct sigaction sa;

23:

24:  if (!(child = fork())) {

25:   memset(&sa, 0, sizeof(sa));

26:   sa.sa_handler = catch_signal;

27:   sigemptyset(&sa.sa_mask);

28:   sa.sa_flags = SA_RESTART;

29:

30:   sigaction(SIGALRM, &sa, NULL);

31:

32:   memset(&it, 0, sizeof(it));

33:   it.it_interval.tv_sec = interval;

34:   it.it_value.tv_sec = interval;

35:   setitimer(ITIMER_REAL, &it, NULL);

36:

37:   while (1) pause();

38:  }

39:

40:  return child;

41: }

42:

43: void stop_timer(pid_t child) {

44:  kill(child, SIGTERM);

45: }

46:

47: int main (int argc, const char **argv) {

48:  pid_t timer = 0;

49:

50:  printf("Демонстрация интервальных таймеров для 10 секунд, "

51:   "ожидайте... ");

52:  timer = start_timer(1);

53:  sleep(10);

54:  stop_timer(timer);

55:  printf("Готово. ");

56:

57:  return 0;

58: }