ПРИМЕЧАНИЕ

С сигналами в Unix всегда была связана одна проблема: действие сигнала сбрасывалось на установленное по умолчанию каждый раз при отправке сигнала (раздел 10.4 [21]). Обычно первой функцией, вызываемой обработчиком сигнала, была signal, переопределявшая обработчик. Это создавало небольшой временной промежуток между отправкой сигнала и переопределением обработчика, в который процесс мог быть завершен при повторном появлении того же сигнала. На первый взгляд может показаться, что та же проблема должна возникать и при использовании mq_notify, поскольку процесс должен перерегистрироваться каждый раз после появления уведомления. Однако очереди сообщений отличаются по своим свойствам от сигналов, поскольку необходимость отправки уведомления не может возникнуть, пока очередь не будет пуста. Следовательно, необходимо аккуратно перерегистрироваться на получение уведомления до считывания пришедшего сообщения из очереди.

<p>Пример: простая программа с уведомлением</p>

Прежде чем углубляться в тонкости сигналов реального времени и потоков Posix, мы напишем простейшую программу, включающую отправку сигнала SI6USR1 при помещении сообщения в пустую очередь. Эта программа приведена в листинге 5.8, и мы отметим, что она содержит ошибку, о которой мы вскоре поговорим подробно.

Листинг 5.8. Отправка sigusr1 при помещении сообщения в пустую очередь (неправильная версия программы)

//pxmsg/mqnotifysigl.c

1  #include "unpipc.h"

2  mqd_t mqd;

3  void *buff;

4  struct mq_attr attr;

5  struct sigevent sigev;

6  static void sig_usrl(int);

7  int

8  main(int argc, char **argv)

9  {

10  if (argc != 2)

11   err_quit("usage: mqnotifysig1 ");

12  /* открываем очередь, получаем атрибуты, выделяем буфер */

13  mqd = Mq_open(argv[1], O_RDONLY);

14  Mq_getattr(mqd, &attr);

15  buff = Malloc(attr.mq_msgsize);

16  /* устанавливаем обработчик, включаем уведомление */

17  Signal(SIGUSR1, sig_usr1);

18  sigev.sigev_notify = SIGEV_SIGNAL;

19  sigev.sigev_signo = SIGUSR1;

20  Mq_notify(mqd, &sigev);

21  for (;;)

22   pause(); /* все делает обработчик */

23  exit(0);

24 }

25 static void

26 sig_usr1(int signo)

27 {

28  ssize_t n;

29  Mq_notify(mqd, &sigev); /* сначала перерегистрируемся */

30  n = Mq_receive(mqd, buff, attr.mq_msgsize, NULL);

31  printf("SIGUSR1 received, read %ld bytes\n", (long) n);

32  return;

33 }

Объявление глобальных переменных

2-6 Мы объявляем несколько глобальных переменных, используемых совместно функцией main и нашим обработчиком сигнала (sig_usr1).

Открытие очереди, получение атрибутов, выделение буфера чтения

12-15 Мы открываем очередь сообщений, получаем ее атрибуты и выделяем буфер считывания соответствующего размера.

Установка обработчика сигнала, включение уведомления

16-20 Сначала мы устанавливаем свой обработчик для сигнала SIGUSR1. Мы присваиваем полю sigev_notify структуры sigevent значение SIGEV_SIGNAL, что говорит системе о необходимости отправки сигнала, когда очередь из пустой становится непустой. Полю sigev_signo присваивается значение, соответствующее тому сигналу, который мы хотим получить. Затем вызывается функция mq_notify.

Бесконечный цикл
Перейти на страницу:

Все книги серии Мастер-класс

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