Функция mq_notify() подписывает вызывающий процесс на оповещения, передающиеся ему при появлении сообщения в пустой очереди, на которую ссылается дескриптор mqdes.
#include
int mq_notify(mqd_t
Возвращает 0 при успешном завершении или -1 при ошибке
Аргумент notification определяет, как именно процесс будет уведомлен. Прежде чем переходить к подробностям, стоит сделать несколько замечаний, касающихся механизма оповещения.
• Только один процесс может быть подписан на получение оповещений из определенной очереди. Если на них уже подписан другой процесс, то дальнейшие попытки подписаться завершаться неудачно (вызов mq_notify() вернет ошибку EBUSY).
• Зарегистрированный процесс оповещается только о появлении сообщения в ранее пустой очереди. Если на момент регистрации очередь уже содержит сообщения, то оповещения начнут приходить лишь после того, как она опустеет и получит новое сообщение.
• После отправки оповещения подписка процесса аннулируется, в результате чего любой другой процесс может подписаться на данную очередь. Иными словами, если процесс желает и дальше получать оповещения, то должен каждый раз заново выполнять подписку, используя вызов mq_notify().
• Зарегистрированный процесс оповещается только в том случае, если нет никакого другого процесса, заблокированного обращением к очереди с помощью вызова mq_receive(). При наличии такого процесса он сначала должен будет прочитать сообщение, а подписчик останется зарегистрированным.
• Процесс может вручную отменить подписку на оповещения из заданной очереди, вызвав функцию mq_notify() со значением NULL в качестве аргумента notification.
В подразделе 23.6.1 вы уже познакомились со структурой sigevent, которая используется в качестве типа аргумента notification. Здесь она представлена в упрощенном виде, только с теми полями, которые имеют отношение к функции mq_notify():
union sigval {
int sival_int; /* Вспомогательное целочисленное значение */
void *sival_ptr; /* Указатель на данные оповещения */
};
struct sigevent {
int sigev_notify; /* Способ оповещения */
int sigev_signo; /* Сигнал оповещения для SIGEV_SIGNAL */
union sigval sigev_value; /* Значение, передающееся в обработчик
сигнала или функцию в отдельном потоке */
void (*sigev_notify_function) (union sigval);
/* Функция, доставляющая оповещение в отдельном потоке */
void *sigev_notify_attributes; /* Указатель на 'pthread_attr_t' */
};
Поле sigev_notify этой структуры принимает одно из следующих значений.
• SIGEV_NONE — подписывает процесс на оповещения, но при появлении сообщения в ранее пустой очереди не уведомляет о данном факте. И, как обычно, после этого подписка отменяется.
• SIGEV_SIGNAL — оповещает процесс, генерируя сигнал, указанный в поле sigev_signo. Если это сигнал реального времени, то данные, передающиеся вместе с ним, указываются в поле sigev_value (см. подраздел 22.8.1). Их можно извлечь из поля si_value структуры siginfo_t, которая передается в обработчик сигнала или возвращается вызовами sigwaitinfo() или sigtimedwait(). В структуре siginfo_t также заполняются следующие поля: si_code (значение SI_MESGQ), si_signo (номер сигнала), si_pid (идентификатор процесса, пославшего сообщение) и si_uid (реальный ID пользователя, от имени которого было послано сообщение). В ряде реализаций поля si_pid и si_uid не устанавливаются.
• SIGEV_THREAD — оповещает процесс путем вызова в отдельном потоке функции, указанной в поле sigev_notify_function. Полю sigev_notify_attributes можно присвоить либо NULL, либо указатель на структуру pthread_attr_t, описывающую атрибуты нового потока (см. раздел 29.8). Объединение sigval, указанное в поле sigev_value, передается в качестве аргумента данной функции.
48.6.1. Получение оповещения в виде сигнала
В листинге 48.6 приводится пример оповещения, основанного на сигнале. Данная программа выполняет следующие шаги.
1. Открывает в неблокирующем режиме очередь сообщений, имя которой указано в командной строке
2. Блокирует сигнал-оповещение (SIGUSR1) и устанавливает для него обработчик
3. Выполняет начальный вызов mq_notify(), чтобы подписать процесс на получение оповещений
4. Входит в бесконечный цикл и в нем выполняет следующие действия:
• делает вызов sigsuspend(), который разблокирует сигнал-оповещение и ждет, пока он не будет перехвачен
• вызывает функцию mq_notify(), чтобы снова подписать данный процесс на оповещения
• выполняет цикл while, который опустошает очередь, пытаясь прочитать из нее как можно больше сообщений
Листинг 48.6. Получение оповещения в виде сигнала
pmsg/mq_notify_sig.c
#include
#include