next up previous contents
Next: Управление очередями сообщений Up: Очереди сообщений Previous: Структуры данных очередей сообщений   Contents

Создание очередей сообщений

Cинтаксис системного вызова msgget выглядит так:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgget ( key_t key,int msgflg);

Тип key_t описан во включаемом файле <sys/types.h> при помощи typedef как целый тип.

Целочисленное значение, возвращаемое в случае успешного завершения системного вызова, есть идентификатор очереди сообщений (msqid). В случае неудачи результат равен -1.

Новый идентификатор msqid, очередь сообщений и ассоциированная с ней структура данных выделяются в каждом из двух случаев:

Целое число, передаваемое в качестве аргумента msgflg, удобно рассматривать как восьмеричное. Оно задает права на выполнение операций и флаги. Права на выполнение операций - это права на чтение из очереди и запись в нее (т. е. на прием или посылку сообщений) для владельца, членов группы и прочих пользователей. В табл. 2 сведены возможные элементарные права и соответствующие им восьмеричные значения:


Таблица 2. Права доступа к очередям.


Права на операции Восьмеричное значение
Чтение для владельца 0400
Запись для владельца 0200
Чтение для группы 0040
Запись для группы 0020
Чтение для остальных 0004
Запись для остальных 0002

В каждом конкретном случае нужная комбинация прав задается как результат операции побитного ИЛИ для значений, соответствующих элементарным правам. Так, например, правам на чтение и запись для владельца и на чтение для членов группы и прочих пользователей соответствует восьмеричное число 0644. Следует отметить полную аналогию с правами доступа к файлам.

Флаги определены во включаемом файле <sys/ipc.h>. В табл. 3 сведены мнемонические имена флагов и соответствующие им восьмеричные значения:


Таблица 3. Флаги работы с очередями.


Флаг Восьмеричное значение
IPC_CREAT 0001000
IPC_EXCL 0002000

Значение аргумента msgflg в целом является, следовательно, результатом операции побитного ИЛИ (операция | в языке C) для прав на выполнение операций и флагов, например:

msqid = msgget (key, (IPC_CREAT | 0644));

msqid = msgget (key, (IPC_CREAT | IPC_EXCL | 0400));

Как уже указывалось, системный вызов вида
msqid = msgget (IPC_PRIVATE, msgflg); приведет к попытке выделения нового идентификатора очереди сообщений и ассоциированной информации, независимо от значения аргумента msgflg. Попытка может быть неудачной только из-за превышения системного лимита на общее число очередей сообщений, задаваемого настраиваемым параметром MSGMNI.

При использовании флага IPC_EXCL в сочетании с IPC_CREAT системный вызов msgget завершается неудачей в том и только в том случае, когда с указанным ключом key уже ассоциирован идентификатор. Флаг IPC_EXCL необходим, чтобы предотвратить ситуацию процесса, когда надежда получить новый (уникальный) идентификатор очереди сообщений не сбывается. Иными словами, когда используются и IPC_CREAT и IPC_EXCL, при успешном завершении системного вызова обязательно возвращается новый идентификатор msqid.

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

Программа-пример для msgget, приведенная ниже, управляется посредством меню. Она позволяет поупражняться со всевозможными комбинациями системного вызова msgget, проследить, как передаются аргументы и получаются результаты. Имена переменных выбраны максимально близкими к именам, используемым в спецификации синтаксиса системного вызова, что облегчает чтение программы.

Выполнение программы начинается с приглашения ввести шестнадцатеричный ключ key, восьмеричный код прав на операции и, наконец, выбираемую при помощи меню комбинацию флагов. В меню предлагаются все возможные комбинации, даже бессмысленные, что позволяет при желании проследить за реакцией на ошибку. Затем выбранные флаги комбинируются с правами на операции, после чего выполняется системный вызов, результат которого заносится в переменную msqid. Если значение msqid равно -1, выдается сообщение об ошибке и выводится значение внешней переменной errno. Если ошибки не произошло, выводится значение полученного идентификатора очереди сообщений:

/* Программа иллюстрирует

возможности системного вызова msgget()

(получение идентификатора очереди сообщений) */

 

#include <stdio.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

#include <errno.h>

 

main ()

{

  key_t key; /* Тип описан как целое */

  int opperm, flags; /* Права на операции и флаги */

  int msgflg, msqid;

 

  /* Ввести требуемый ключ */

  printf ("\nВведите шестнадцатеричный ключ: ");

  scanf ("%x", &key);

 

  /* Ввести права на операции */

  printf ("\nВведите права на операции ");

  printf ("в восьмеричной записи: ");

  scanf ("%o", &opperm);

 

  /* Установить требуемые флаги */

  printf ("\nВведите код, соответствущий ");

  printf ("нужной комбинации флагов:\n");

  printf (" Нет флагов = 0\n");

  printf (" IPC_CREAT = 1\n");

  printf (" IPC_EXCL = 2\n");

  printf (" IPC_CREAT и IPC_EXCL = 3\n");

  printf (" Выбор = ");

 

  /* Получить флаги, которые нужно установить */

  scanf ("%d", &flags);

 

  /* Проверить значения */

  printf ("\nключ = 0x%x, права = 0%o, флаги = %d\n",

          key, opperm, flags);

 

  /* Объединить флаги с правами на операции */

  switch (flags) {

  case 0: /* Флаги не устанавливать */

          msgflg = (opperm | 0);

          break;

  case 1: /* Установить флаг IPC_CREAT */

          msgflg = (opperm | IPC_CREAT);

          break;

  case 2: /* Установить флаг IPC_EXCL */

          msgflg = (opperm | IPC_EXCL);

          break;

  case 3: /* Установить оба флага */

          msgflg = (opperm | IPC_CREAT | IPC_EXCL);

  }

 

  /* Выполнить системный вызов msgget */

  msqid = msgget (key, msgflg);

  if (msqid == -1) {

  /* Сообщить о неудачном завершении */

    printf ("\nmsgget завершился неудачей!\n"

  printf ("Код ошибки = %d\n", errno);

  }

  else

  /* При успешном завершении сообщить msqid */

  printf ("\nИдентификатор msqid = %d\n", msqid);

  exit (0);

}


next up previous contents
Next: Управление очередями сообщений Up: Очереди сообщений Previous: Структуры данных очередей сообщений   Contents
2004-06-22