4. При помещении сообщения в пустую очередь, для которой имеется зарегистрированный на уведомление процесс, оно будет отправлено только в том случае, если нет заблокированных в вызове mq_receive для этой очереди процессов. Таким образом, блокировка в вызове mq_receive имеет приоритет перед любой регистрацией на уведомление.
5. При отправке уведомления зарегистрированному процессу регистрация снимается. Процесс должен зарегистрироваться снова (если в этом есть необходимость), вызвав mq_notify еще раз.
ПРИМЕЧАНИЕ
С сигналами в Unix всегда была связана одна проблема: действие сигнала сбрасывалось на установленное по умолчанию каждый раз при отправке сигнала (раздел 10.4 [21]). Обычно первой функцией, вызываемой обработчиком сигнала, была signal, переопределявшая обработчик. Это создавало небольшой временной промежуток между отправкой сигнала и переопределением обработчика, в который процесс мог быть завершен при повторном появлении того же сигнала. На первый взгляд может показаться, что та же проблема должна возникать и при использовании mq_notify, поскольку процесс должен перерегистрироваться каждый раз после появления уведомления. Однако очереди сообщений отличаются по своим свойствам от сигналов, поскольку необходимость отправки уведомления не может возникнуть, пока очередь не будет пуста. Следовательно, необходимо аккуратно перерегистрироваться на получение уведомления
Пример: простая программа с уведомлением
Прежде чем углубляться в тонкости сигналов реального времени и потоков Posix, мы напишем простейшую программу, включающую отправку сигнала SI6USR1 при помещении сообщения в пустую очередь. Эта программа приведена в листинге 5.8, и мы отметим, что она содержит ошибку, о которой мы вскоре поговорим подробно.
//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\n", (long) n);
32 return;
33 }
2-6 Мы объявляем несколько глобальных переменных, используемых совместно функцией main и нашим обработчиком сигнала (sig_usr1).
12-15 Мы открываем очередь сообщений, получаем ее атрибуты и выделяем буфер считывания соответствующего размера.