Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2557 / 712 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 8:

Средства межпроцессного взаимодействия

Для работы с очередями сообщений стандарт POSIX-2001 предусматривает следующие функции (см. листинг 8.23): msgget() (получение идентификатора очереди сообщений ), msgctl() ( управление очередью сообщений ), msgsnd() ( отправка сообщения ) и msgrcv() ( прием сообщения ).

#include <sys/msg.h>
int msgget (key_t key, int msgflg);
int msgsnd (int msqid, const void *msgp, 
            size_t msgsz, int msgflg);
ssize_t msgrcv (int msqid, void *msgp, 
                size_t msgsz, long msgtyp, 
				int msgflg);
int msgctl (int msqid, int cmd, 
            struct msqid_ds *buf);
Листинг 8.23. Описание функций для работы с очередями сообщений.

Структура msqid_ds, ассоциированная с идентификатором очереди сообщений, должна содержать по крайней мере следующие поля.

struct ipc_perm msg_perm;       
/* Данные о правах доступа 
к очереди сообщений */
msgqnum_t       msg_qnum;       
/* Текущее количество сообщений в очереди */
msglen_t        msg_qbytes;     
/* Максимально допустимый суммарный 
размер сообщений в очереди */
pid_t           msg_lspid;      
/* Идентификатор процесса, отправившего 
последнее сообщение */
pid_t           msg_lrpid;      
/* Идентификатор процесса, принявшего 
последнее сообщение */
time_t          msg_stime;      
/* Время последней отправки */
time_t          msg_rtime;      
/* Время последнего приема */
time_t          msg_ctime;      
/* Время последнего изменения 
посредством msgctl() */

Перейдем к детальному рассмотрению функций для работы с очередями сообщений.

Функция msgget() возвращает идентификатор очереди сообщений, ассоциированный с ключом key. Новая очередь, ее идентификатор и соответствующая структура msqid_ds создаются для заданного ключа, если значение аргумента key равно IPC_PRIVATE или очередь еще не ассоциирована с ключом, а в числе флагов msgflg задан IPC_CREAT.

Если необходима уверенность в том, что очередь с указанным ключом создается заново, в дополнение к флагу IPC_CREAT следует установить IPC_EXCL. Тогда попытка получить идентификатор уже существующий очереди завершится неудачей.

Структура msqid_ds для новой очереди инициализируется следующим образом.

  • Значения полей msg_perm.cuid, msg_perm.uid, msg_perm.cgid и msg_perm.gid устанавливаются равными действующим идентификаторам пользователя и группы вызывающего процесса.
  • Младшие девять бит поля msg_perm.mode устанавливаются равными младшим девяти битам значения msgflg.
  • Поля msg_qnum, msg_lspid, msg_lrpid, msg_stime и msg_rtime обнуляются.
  • В поле msg_ctime помещается текущее время, а в поле msg_qbytes - определенный в системе лимит.

Один из тонких вопросов, связанных с созданием очереди сообщений, заключается в выборе ключа. Всем процессам, которые намереваются работать с общей очередью сообщений, для получения идентификатора msqid необходимо знать ключ очереди. Задание ключа одинаковым константным значением во всех этих программах небезопасно, поскольку может оказаться так, что тот же ключ будет случайно задействован и другими программами. Как одно из возможных решений рекомендуется использование функции ftok(), вычисляющей действительно "уникальный" ключ.

В листинге 8.24 приведен простейший пример программы, где создается очередь сообщений с правами доступа, указанными в командной строке.

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>

/* Программа создает очередь сообщений.             */
/* В командной строке задаются имя файла для ftok() */
/* и режим доступа к очереди сообщений              */

#define FTOK_CHAR       'G'

int main (int argc, char *argv []) {
 key_t key;
 int msqid;
 int mode = 0;

 if (argc != 3) {
   fprintf (stderr, "Использование: %s маршрутное_имя режим_доступа\n", argv [0]);
   return (1);
 }

 if ((key = ftok (argv [1], FTOK_CHAR)) == (key_t) (-1)) {
   perror ("FTOK");
   return (2);
 }
 (void) sscanf (argv [2], "%o", (unsigned int *) &mode);

 if ((msqid = msgget (key, IPC_CREAT | mode)) < 0) {
   perror ("MSGGET");
   return (3);
 }

 return 0;
}
Листинг 8.24. Пример программы, создающей очередь сообщений.

Если после выполнения этой программы воспользоваться командой ipcs -q, то результат может выглядеть так, как показано в листинге 8.25.

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages
0x47034bac 163840     galat      644        0            0
Листинг 8.25. Возможный результат опроса статуса очередей сообщений.

Удалить созданную очередь из системы, соответствующей стандарту POSIX-2001, можно командой ipcrm -q 163840.

Операции отправки / приема сообщений выполняют функции msgsnd() и msgrcv() ; msgsnd() помещает сообщения в очередь, а msgrcv() читает и "достает" их оттуда.

В обоих случаях первый аргумент задает идентификатор очереди; второй является указателем на содержащую сообщение структуру. Сообщение состоит из двух частей: текста (последовательности байт) и так называемого типа (положительного целого числа). Тип, указанный во время отправки, используется впоследствии при выборе сообщения из очереди. Аргумент msgsz определяет длину сообщения; аргумент msgflg задает флаги.

В зависимости от значения, указанного в качестве аргумента msgtyp функции msgrcv(), из очереди выбирается то или иное сообщение. Если значение аргумента равно нулю, запрашивается первое сообщение в очереди, если больше нуля - первое сообщение типа msgtyp, а если меньше нуля - первое сообщение наименьшего из типов, не превышающих абсолютную величину аргумента msgtyp. Пусть, например, в очередь последовательно помещены сообщения с типами 5, 3 и 2. Тогда вызов msgrcv (msqid, msgp, size, 0, flags) выберет из очереди сообщение с типом 5, поскольку оно отправлено первым; вызов msgrcv (msqid, msgp, size, -4, flags) - последнее сообщение, так как 2 - это наименьший из возможных типов в указанном диапазоне; наконец, вызов msgrcv (msqid, msgp, size, 3, flags) - сообщение с типом 3.

Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?