Книга: UNIX: взаимодействие процессов

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

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

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

Оглавление книги


Генерация: 0.064. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз