$ ./pmsg_send /mq msg-b 0
$ ./pmsg_send /mq msg-c 10
Затем последовательно выполним несколько команд, чтобы извлечь эти сообщения из очереди:
$ ./pmsg_receive /mq
Read 5 bytes; priority = 10
msg-c
$ ./pmsg_receive /mq
Read 5 bytes; priority = 5
msg-a
$ ./pmsg_receive /mq
Read 5 bytes; priority = 0
msg-b
Как видно из вывода, приведенного выше, сообщения были извлечены в порядке их приоритета.
На этот момент очередь является пустой. Если выполнить еще одно блокирующее извлечение, то операция будет приостановлена:
$ ./pmsg_receive /mq
С другой стороны, если выполнить неблокирующее извлечение, то вызов немедленно вернет сообщение об ошибке:
$ ./pmsg_receive — n /mq
ERROR [EAGAIN/EWOULDBLOCK Resource temporarily unavailable] mq_receive
Листинг 48.5. Чтение сообщений из очереди POSIX
pmsg/pmsg_receive.c
#include
#include
#include "tlpi_hdr.h"
static void
usageError(const char *progName)
{
fprintf(stderr, "Usage: %s [-n] mq-name\n", progName);
fprintf(stderr, " — n Use O_NONBLOCK flag\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
int flags, opt;
mqd_t mqd;
unsigned int prio;
void *buffer;
struct mq_attr attr;
ssize_t numRead;
flags = O_RDONLY;
while ((opt = getopt(argc, argv, "n"))!= -1) {
switch (opt) {
case 'n': flags |= O_NONBLOCK; break;
default: usageError(argv[0]);
}
}
if (optind >= argc)
usageError(argv[0]);
mqd = mq_open(argv[optind], flags);
if (mqd == (mqd_t) -1)
errExit("mq_open");
if (mq_getattr(mqd, &attr) == -1)
errExit("mq_getattr");
buffer = malloc(attr.mq_msgsize);
if (buffer == NULL)
errExit("malloc");
numRead = mq_receive(mqd, buffer, attr.mq_msgsize, &prio);
if (numRead == -1)
errExit("mq_receive");
printf("Read %ld bytes; priority = %u\n", (long) numRead, prio);
if (write(STDOUT_FILENO, buffer, numRead) == -1)
errExit("write");
write(STDOUT_FILENO, "\n", 1);
exit(EXIT_SUCCESS);
}
pmsg/pmsg_receive.c
48.5.3. Отправка и получение сообщений с ограниченным временем ожидания
Функции mq_timedsend() и mq_timedreceive() являются прямыми аналогами mq_send() и mq_receive(), но с одним отличием: если операция не может быть выполнена немедленно и если среди атрибутов сообщения не указан флаг O_NONBLOCK, аргумент abs_timeout определяет продолжительность блокирования вызова.
#define _XOPEN_SOURCE 600
#include
#include
int mq_timedsend(mqd_t
unsigned int
Возвращает 0 при успешном завершении или -1 при ошибке
ssize_t mq_timedreceive(mqd_t
unsigned int *
const struct timespec *
Возвращает объем полученного сообщения (в байтах) или -1 при ошибке
Аргумент abs_timeout представляет собой структуру timespec (см. подраздел 23.4.2), которая задает время ожидания в виде количества секунд и наносекунд, прошедших с начала «эры UNIX». Для указания относительного времени ожидания можно воспользоваться функцией clock_gettime(), чтобы извлечь текущее значение часов CLOCK_REALTIME и затем добавить к нему необходимый период времени, получив тем самым структуру timespec, инициализированную должным образом.
Если вызов функции mq_timedsend() или mq_timedreceive() не завершается вовремя, то он возвращает ошибку ETIMEDOUT. Если в Linux аргументу abs_timeout присвоить значение NULL, то время ожидания будет неограниченным. Однако такая возможность не предусмотрена стандартом SUSv3, и портируемые приложения не могут на нее полагаться.
Функции mq_timedsend() и mq_timedreceive() изначально появились в стандарте POSIX.1d (1999) и доступны не во всех реализациях UNIX.
Особенность, которая отличает очереди сообщений POSIX от их аналогов из System V, состоит в возможности получать асинхронные оповещения о появлении в ранее пустой очереди нового сообщения (то есть очередь перестает быть пустой). Это значит, что вместо выполнения блокирующего вызова mq_receive() или маркировки дескриптора очереди сообщений как неблокирующего с последующими регулярными «опросами» очереди процесс может подписаться на оповещения о приходе сообщений и заняться чем-нибудь другим. Оповещение можно получать либо в виде сигнала, либо путем вызова функции в отдельном потоке.
Оповещения, предоставляемые очередями сообщений POSIX, похожи на механизм оповещений для POSIX-таймеров, описанный в разделе 23.6 (оба этих программных интерфейса изначально появились в стандарте POSIX.1b).