Хотя программа из предыдущего примера работает правильно, можно повысить ее эффективность. Программа использует sigsuspend для блокировки в ожидании прихода сообщения. При помещении сообщения в пустую очередь вызывается сигнал, основной поток останавливается, запускается обработчик, который устанавливает флаг mqflag, затем снова запускается главный поток, он обнаруживает, что значение mqflag отлично от нуля, и считывает сообщение. Более простой и эффективный подход заключается в блокировании в функции, ожидающей получения сигнала, что не требует вызова обработчика только для установки флага. Эта возможность предоставляется функцией sigwait:
#include
int sigwait(const sigset_t
/* Возвращает 0 в случае успешного завершения, –1 – в случае ошибки */
Перед вызовом sigwait мы блокируем некоторые сигналы. Набор блокируемых сигналов указывается в качестве аргумента set. Функция sigwait блокируется, пока не придет по крайней мере один из этих сигналов. Когда он будет получен, функция возвратит его. Значение этого сигнала сохраняется в указателе
В листинге 5.11 приведен текст программы, использующей mq_notifу и sigwait.
//pxmsg/mqnotifysig4.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 int signo;
6 mqd_t mqd;
7 void *buff;
8 ssize_t n;
9 sigset_t newmask;
10 struct mq_attr attr;
11 struct sigevent sigev;
12 if (argc != 2)
13 err_quit("usage: mqnotifysig4
14 /* открытие очереди, получение атрибутов, выделение буфера */
15 mqd = Mq_open(argv[1], O_RDONLY | O_NONBLOCK);
16 Mq_getattr(mqd, &attr);
17 buff = Malloc(attr.mq_msgsize);
18 Sigemptyset(&newmask);
19 Sigaddset(&newmask, SIGUSR1);
20 Sigprocmask(SIG_BLOCK, &newmask, NULL); /* блокируем SIGUSR1 */
21 /* установка обработчика, включение уведомления */
22 sigev.sigev_notify = SIGEV_SIGNAL;
23 sigev.sigev_signo = SIGUSR1;
24 Mq_notify(mqd, &sigev);
25 for (;;) {
26 Sigwait(&newmask, &signo);
27 if (signo == SIGUSR1) {
28 Mq_notify(mqd, &sigev); /* перерегистрируемся */
29 while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) {
30 printf("read %ld bytes\n", (long) n);
31 }
32 if (errno != EAGAIN)
33 err_sys("mq_receive error");
34 }
35 }
36 exit(0);
37 }
18-20 Инициализируется один набор сигналов, содержащий только SIGUSR1, а затем этот сигнал блокируется sigprocmask.
26-34 Мы блокируем выполнение программы и ждем прихода сигнала, вызвав sigwait. При получении сигнала SIGUSR1 мы перерегистрируемся на уведомление и считываем все доступные сообщения.