Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учеб.пос.СП.doc
Скачиваний:
28
Добавлен:
31.03.2015
Размер:
1.33 Mб
Скачать
    1. Системные вызовы для работы с очередями сообщений posix

Существует два набора системных вызовов для работы с очередями сообщений, семафорами и общей памятью. Самый старый из них называется System V IPC, более современный - POSIX IPC. В этом разделе мы рассмотрим POSIX IPC. Проблема именования является скользким местом при работе с очередями сообщений POSIX. Сначала рассмотрим системный вызов mq_open, который открывает очередь сообщений:

mq_open - открывает очередь сообщений

#include <mqueue.h>

mqd_t mq_open (

const char *name, /* имя POSIX IPC */

int flags /* флаги (за исключением O_CREAT) */

);

/* Возвращает дескриптор очереди или -1 в случае ошибки (код ошибки - в errno) */

mqd_t mq_open (

const char *name, /* имя POSIX IPC */

int flags, /* флаги (включая O_CREAT) */

mode_t perms, /* права доступа */

struct mq_attr *attr /* атрибуты или NULL */

);

/* Возвращает дескриптор очереди или -1 в случае ошибки (код ошибки - в errno) */

struct mq_attr - структура для использования в вызовах mq_open, mq_getattr и mq_setattr

struct mq_attr {

long mq_flags; /* флаги */

long mq_maxmsg; /* максимальное число сообщений */

long mq_msgsize; /* максимальный размер одного сообщения */

long mq_curmsgs; /* количество сообщений в очереди */

}

Аргумент flags может быть собран с помощью тех же макросов, что и для вызова open (например, O_CREAT):

  • в зависимости от того, как будет использоваться очередь, можно использовать один из макросов: O_RDONLY, O_WRONLY или O_RDWR;

  • флаг O_CREAT используется для создания новой очереди, если таковой не существует. В этом случае используется вторая форма обращения к системному вызову;

  • с флагом O_EXCL новая очередь создается только тогда, когда она не существует. В противном случае будет возвращен признак ошибки;

  • флаг O_NONBLOCK создает очередь без возможности блокировки. Это означает, что mq_send и mq_receive будут возвращать признак ошибки с кодом EAGAIN, если очередь переполнена или пуста. По умолчанию очередь создается с возможностью блокировки.

Право на чтение и запись означает возможность извлекать сообщения из очереди и помещать их в очередь соответственно. Как и файлы, очереди имеют идентификаторы владельца и группы, они устанавливаются в соответствии с действующими идентификаторами процесса, создавшего очередь. При создании новой очереди с флагом O_CREAT, если аргумент attr не является пустым указателем, очереди присваиваются два первых атрибута из структуры mq_attr. Эти атрибуты устанавливают максимальное число сообщений в очереди и максимальный размер одного сообщения, которое может быть помещено в очередь. В большинстве реализаций очередь сообщений представляет собой связанный список, поэтому на момент вызова mq_open исчерпание свободного пространства не возникает, так как, невзирая на величину атрибутов, очередь фактически пуста. Если в аргументе attr передается пустой указатель, атрибуты очереди устанавливаются в значения по умолчанию, характерные для той или иной системы.

Закрывается очередь обращением к системному вызову mq_close:

mq_close - закрывает очередь сообщений

#include <mqueue.h>

int mq_close (

mqd_t mqd /* дескриптор очереди */

);

/* Возвращает 0 в случае успеха, -1 в случае ошибки (код ошибки - в errno) */

Очереди сообщений POSIX остаются существовать в системе до тех пор, пока не произойдет перезагрузка системы или пока не будет произведено обращение к системному вызову mq_unlink:

mq_unlink - удаляет очередь сообщений

#include <mqueue.h>

int mq_unlink (

const char *name /* имя POSIX IPC */

);

/* Возвращает 0 в случае успеха, -1 в случае ошибки (код ошибки - в errno) */

Системный вызов mq_unlink делает имя очереди недоступным сразу же, но фактическое ее разрушение откладывает до того момента, когда будет закрыт последний ссылающийся на нее дескриптор.

Следующий системный вызов mq_send дает возможность послать сообщение:

mq_send - помещает сообщение в очередь

#include <mqueue.h>

int mq_ send(

mqd_t mqd, /* дескриптор очереди */

const char *msg, /* сообщение */

size_t msgsize, /* размер сообщения */

unsigned priority /* приоритет */

);

/* Возвращает 0 в случае успеха, -1 в случае ошибки (код ошибки - в errno) */

Системный вызов mq_send помещает сообщение размером msgsize в очередь впереди сообщений с более низким приоритетом, но позади сообщений с тем же самым приоритетом. Вызов mq_send может быть заблокирован, если очередь заполнена до отказа, разумеется, при условии, что флаг O_NONBLOCK сброшен. Прием сообщения производится системным вызовом mq_receive:

mq_receive - извлекает сообщение из очереди

#include <mqueue.h>

ssize_t mq_receive (

mqd_t mqd, /* дескриптор очереди сообщений*/

char *msg, /* буфер для сообщения */

size_t msgsize, /* размер буфера */

unsigned *priorityp /* приоритет принятого сообщения или NULL*/

);

/* Возвращает размер сообщения или -1 в случае ошибки (код ошибки - в errno) */

Аргумент msgsize определяет размер буфера, на который указывает аргумент msg. По адресу priority записывается приоритет принятого сообщения. Полученное сообщение удаляется из очереди, возможность просмотреть сообщение без его извлечения не предусмотрена. Если очередь пуста, mq_receive блокируется при условии, что флаг O_NONBLOCK сброшен.

Работать с несколькими очередями или с очередью и еще чем-нибудь, что может привести к блокировке в системном вызове, очень неудобно, поскольку не имеется возможности выполнить проверку дескриптора очереди с помощью вызова select или poll. Однако можно заставить систему извещать приложение о прибытии нового сообщения посредством сигналов. Сделать это можно с помощью системного вызова mq_notify:

mq_ notify - включает или выключает режим асинхронных уведомлений

#include <mqueue.h>

int mq_ notify (

mqd_t mqd, /* дескриптор очереди */

const struct sigevent *ep /* извещение */

);

/* Возвращает 0 в случае успеха, -1 в случае ошибки (код ошибки - в errno) */

Когда процесс или поток включает режим уведомлений, они будут получать сигнал в момент поступления сообщения в пустую очередь mqd, при условии, что к этому моменту процесс или поток не будут заблокированы в mq_receive - в этом случае произойдет выход из заблокированного mq_receive. Только один процесс или поток могут подписаться на получение уведомлений. Попытка включить режим уведомления из второго процесса или потока потерпит неудачу. Режим уведомлений отключается, когда процесс или поток получают сигнал или когда они обращаются к системному вызову mq_ notify с аргументом sigevent равным NULL.

При поступлении сообщения в непустую очередь уведомление процесса не производится, таким образом, mq_ notify не гарантирует отправку сигнала по прибытии каждого сообщения. Например, первое сообщение, помещенное, в пустую очередь, вызовет передачу сигнала процессу, но если до извлечения первого сообщения в очередь поступит второе, то уведомление передано не будет, так как фактически в этот момент очередь не пуста. Таким образом, действия приложения должны быть следующими:

  • после вызова mq_ notify следует извлечь (вызовом mq_receive) все сообщения из очереди, с установленным флагом O_NONBLOCK;

  • после прибытия сигнала необходимо сразу же повторно подписаться на уведомления вызовом mq_ notify и выполнить действия, предусмотренные на предыдущем шаге.

Тип сигнала и другие характеристики уведомления определяются исходя из содержимого структуры sigevent.