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

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

Прежде чем углубляться в тонкости сигналов реального времени и потоков 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 <name>");

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 ", (long) n);

32  return;

33 }

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

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

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

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

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

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

Бесконечный цикл

Функция main после этого зацикливается, и процесс приостанавливается при вызове pause, возвращающей –1 при получении сигнала.

Получение сигнала, считывание сообщения

Обработчик сигнала вызывает mq_notify для перерегистрации, считывает сообщение и выводит его длину. В этой программе мы игнорируем приоритет полученного сообщения. 

ПРИМЕЧАНИЕ

Оператор return в конце sig_usr1 не требуется, поскольку возвращаемое значение отсутствует, а конец текста функции неявно предусматривает возвращение в вызвавшую программу. Тем не менее автор всегда записывает return явно, чтобы указать, что возвращение из этой функции может происходит с особенностями. Например, может произойти преждевременный возврат (с ошибкой EINTR) в потоке, обрабатывающем сигнал. 

Запустим теперь эту программу в одном из окон

solaris % mqcreate /test1

solaris % mqnotifysig1 /test1

и затем выполним следующую команду в другом окне

solaris % mqsend /test1 50 16

Как и ожидалось, программа mqnotifysig1 выведет сообщение: SIGUSR1 received, read 50 bytes.

Мы можем проверить, что только один процесс может быть зарегистрирован на получение уведомления в любой момент, запустив копию пpoгрaммы в другом окне:

solaris % mqnotifysig1 /test1

mq_notify error: Device busy

Это сообщение соответствует коду ошибки EBUSY.

Данный текст является ознакомительным фрагментом.