Пример: уведомление сигналом с отключением блокировки
Исправить описанную выше ошибку можно, отключив блокировку операции считывания сообщений. Листинг 5.10 содержит измененную версию программы из листинга 5.9. Новая программа считывает сообщения в неблокируемом режиме.
Листинг 5.10. Использование уведомления с помощью сигнала для считывания сообщения из очереди сообщений Posix
Открытие очереди сообщений в режиме отключенной блокировки
15-18 Первое изменение в программе: при открытии очереди сообщений указывается флаг O_NONBLOCK.
Считывание всех сообщений из очереди
34-38 Другое изменение: mq_receive вызывается
в цикле, считывая все сообщения в очереди, пока не будет возвращена ошибка с кодом EAGAIN, означающая отсутствие сообщений в очереди.
Пример: уведомление с использованием sigwait вместо обработчика
Хотя программа из предыдущего примера работает правильно, можно повысить ее эффективность. Программа использует sigsuspend для блокировки в ожидании прихода сообщения. При помещении сообщения в пустую очередь вызывается сигнал, основной поток останавливается, запускается обработчик, который устанавливает флаг mqflag, затем снова запускается главный поток, он обнаруживает, что значение mqflag отлично от нуля, и считывает сообщение. Более простой и эффективный подход заключается в блокировании в функции, ожидающей получения сигнала, что не требует вызова обработчика только для установки флага. Эта возможность предоставляется функцией sigwait:
#include <signal.h>
int sigwait(const sigset_t *set, int *sig);
/* Возвращает 0 в случае успешного завершения, –1 – в случае ошибки */
Перед вызовом sigwait мы блокируем некоторые сигналы. Набор блокируемых сигналов указывается в качестве аргумента set. Функция sigwait блокируется, пока не придет по крайней мере один из этих сигналов. Когда он будет получен, функция возвратит его. Значение этого сигнала сохраняется в указателе sig, а функция возвращает значение 0. Это называется синхронным ожиданием асинхронного события: мы используем сигнал, но не пользуемся асинхронным обработчиком сигнала.
В листинге 5.11 приведен текст программы, использующей mq_notifу и sigwait.
Листинг 5.11. Использование mq_notify совместно с 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 <name>");
14 /* открытие очереди, получение атрибутов, выделение буфера */