Операционная система UNIX - страница 114

стр.

Рис. 3.19. Мультиплексирование сообщений в одной очереди

Атрибут >msgtype также можно использовать для изменения порядка извлечения сообщений из очереди. Стандартный порядок получения сообщений аналогичен принципу FIFO — сообщения получаются в порядке их записи. Однако используя тип, например, для назначения приоритета сообщений, этот порядок легко изменить.

Пример приложения "Здравствуй, Мир!", использующего сообщения:

Файл описания mesg.h

>#define MAXBUFF 80

>#define PERM 0666


>/* Определим структуру нашего сообщения. Она может отличаться

>   от структуры msgbuf, но должна содержать поле mtype. В данном

>   случае структура сообщения состоит из буфера обмена */

>typedef struct our msgbuf {

> long mtype;

> char buff[MAXBUFF];

>} Message;

Сервер:

>#include

>#include

>#include "mesg.h"


>main() {

> /* Структура нашего сообщения (может отличаться от

>    структуры msgbuf) */

> Message message;

> key_t key;

> int msgid, length, n;


> /* Получим ключ */

> if ((key = ftok("server", 'A')) < 0) {

>  printf("Невозможно получить ключ\n");

>  exit(1);

> }

> /* Тип принимаемых сообщений */

> message.mt_type = 1L;

> /* Создадим очередь сообщений */

> if ((msgid = msgget(key, РЕRМ | IPC_CREAT)) < 0) {

>  printf("Невозможно создать очередь\n");

>  exit(1);

> }

> /* Прочитаем сообщение */

> n =

>  msgrcv(msgid, &message, sizeof(message), message.mtype, 0);

> /* Если сообщение поступило, выведем его содержимое

>    на терминал */

> if (n > 0) {

>  if (write(1, message.buff, n) != n) {

>   printf("Ошибка вывода\n");

>   exit(1);

>  }

> } else {

>  printf("Ошибка чтения сообщения\n");

>  exit(1);

> }


> /* Удалить очередь поручим клиенту */

> exit(0);

>}

Клиент:

>#include

>#include

>#include

>#include "mesg.h"


>main {

> /* Структура нашего сообщения (может отличаться от

>    структуры msgbuf */

> Message message;

> key_t key;

> int msgid, length;


> /* Тип посылаемого сообщения, может использоваться для

>    мультиплексирования */

> message.mtype = 1L;

> /* Получим ключ */

> if ((key = ftok("server", 'A')) < 0) {

>  printf("Невозможно получить ключ\n");

>  exit(1);

> }

> /* Получим доступ к очереди сообщений, очередь уже

>    должна быть создана сервером */

> if ((msgid = msgget(key, 0)) < 0) {

>  printf("Невозможно получить доступ к очереди\n");

>  exit(1);

> }

> /* Поместим строку в сообщение */

> if ((length = sprintf(message.buff,

>  "Здравствуй, Мир!\n")) < 0) {

>  printf("Ошибка копирования в буфер\n");

>  exit(1);

> } /* Передадим сообщение */

> if (msgsnd(msgid, (void*)&message, length, 0) != 0) {

>  printf("Ошибка записи сообщения в очередь\n");

>  exit(1);

> }

> /* Удалим очередь сообщений */

> if (msgctl(msgid, IPC_RMID, 0) < 0) {

>  printf("Ошибка удаления очереди\n");

>  exit(1);

> }

> exit(0);

>}

Семафоры

Для синхронизации процессов, а точнее, для синхронизации доступа нескольких процессов к разделяемым ресурсам, используются семафоры. Являясь одной из форм IPC, семафоры не предназначены для обмена большими объемами данных, как в случае FIFO или очередей сообщений. Вместо этого, они выполняют функцию, полностью соответствующую своему названию — разрешать или запрещать процессу использование того или иного разделяемого ресурса.

Применение семафоров поясним на простом примере. Допустим, имеется некий разделяемый ресурс (например, файл). Необходимо блокировать доступ к ресурсу для других процессов, когда некий процесс производит операцию над ресурсом (например, записывает в файл). Для этого свяжем с данным ресурсом некую целочисленную величину — счетчик, доступный для всех процессов. Примем, что значение 1 счетчика означает доступность ресурса, 0 — его недоступность. Тогда перед началом работы с ресурсом процесс должен проверить значение счетчика. Если оно равно 0 — ресурс занят и операция недопустима — процессу остается ждать. Если значение счетчика равно 1 — можно работать с ресурсом. Для этого, прежде всего, необходимо заблокировать ресурс, т. е. изменить значение счетчика на 0. После выполнения операции для освобождения ресурса значение счетчика необходимо изменить на 1. В приведенном примере счетчик играет роль семафора.

Для нормальной работы необходимо обеспечить выполнение следующих условий: