Семинар 9. Очереди сообщений в UNIX.
(Основывается на лекции 4 и лекции 6)
Предыдущий семинар | Программа курса | Следующий семинар
Программа семинара
Сообщения как средства связи и средства синхронизации процессов.
Очереди сообщений в UNIX как составная часть System V IPC.
Создание очереди сообщений или доступ к уже существующей. Системный вызов msgget().
Реализация примитивов send и receive. Системные вызовы msgsnd() и msgrcv().
Удаление очереди сообщений из системы с помощью команды ipcrm или системного вызова msgctl().
Понятие мультиплексирования. Мультиплексирование сообщений. Модель взаимодействия процессов клиент-сервер. Неравноправность клиента и сервера.
Использование очередей сообщений для синхронизации работы процессов.
Цели занятия
Дать понятие об очередях сообщений в UNIX.
Привить навыки работы с системными вызовами msgget(), msgsnd(), msgrcv(), msgctl(),
Студенты должны понять, что сообщения не обязаны быть текстовыми.
Дать понятие о мультиплексировании и модели клиент-сервер.
Практические работы
Прогон примера с однонаправленной передачей текстовой информации.
Модификация предыдущего примера для передачи числовой информации.
План занятия
Сообщения как средства связи и средства синхронизации
процессов.
На
предыдущих семинарах мы познакомились с такими средствами организации взаимодействия
процессов из состава средств System V IPC, как разделяемая
память и семафоры. Третьим и последним,
наиболее семантически нагруженным средством, входящим в System V IPC, являются
очереди сообщений. На
лекции мы говорили о модели сообщений, как о способе взаимодействия процессов
через линии связи, в котором на передаваемую информацию накладывается определенная
структура так, что процесс, принимающий данные, может четко определить,
где заканчивается одна порция информации и начинается другая. Такая модель
позволяет использовать одну и ту же линию связи для передачи данных в двух
направлениях между несколькими процессами.
Мы
также говорили о возможности использования сообщений с встроенными механизмами
взаимоисключения и блокировки при чтении из пустого буфера и записи в переполненный
буфер для организации синхронизации процессов.
На этом семинаре мы познакомимся с использованием очередей сообщений System
V IPC для обеспечения обеих этих функций.
Очереди сообщений в UNIX как составная часть System V IPC.
Так
как очереди сообщений входят в состав средств System V IPC, то для них верно
все, что говорилось ранее
об этих средствах в целом и уже знакомо нам. Очереди
сообщений, как и семафоры, как и разделяемая память, являются средством
связи с непрямой адресацией, требуют инициализации для организации взаимодействия
процессов и специальных действий для освобождения системных ресурсов по
окончании взаимодействия. Пространством имен очередей сообщений является
то же самое множество значений ключа,
генерируемых с помощью функции ftok().
Для выполнения примитивов send и
receive соответствующим системным вызовам в качестве параметра
передаются IPC дескрипторы
очередей сообщений, однозначно идентифицирующих их во всей вычислительной
системе.
Очереди сообщений располагаются в адресном пространстве ядра операционной
системы в виде однонаправленных списков и имеют ограничение по объему информации,
хранимой в каждой очереди. Каждый элемент списка представляет собой отдельное
сообщение. Сообщения имеют атрибут, называемый типом сообщения. Выборка
сообщений из очереди (выполнение примитива receive)
может осуществляться тремя способами:
В порядке FIFO, независимо от типа сообщения.
В порядке FIFO для сообщений конкретного типа.
Первым выбирается сообщение с минимальным типом, не превышающим некоторого заданного значения, пришедшее ранее всех других сообщений с тем же типом.
Реализация
примитивов send и receive
обеспечивает скрытое от пользователя взаимоисключение во время помещения
сообщения в очередь или его получении из очереди, а также блокировку процесса
при попытке выполнить примитив receive
над пустой очередью или очередью, в которой отсутствуют сообщения запрошенного
типа, или при попытке выполнить примитив send
для очереди, в которой нет свободного места.
Очереди сообщений, как и другие средства System V IPC, позволяют организовывать
взаимодействие процессов, не находящихся одновременно в вычислительной системе.
Создание очереди сообщений или доступ к уже существующей.
Системный вызов msgget().
Для
создания очереди сообщений, ассоциированной с определенным ключом, или доступа
по ключу к уже существующей очереди используется системный вызов msgget(),
являющийся аналогом системных вызовов shmget()
для разделяемой памяти и semget() для
массива семафоров, который возвращает значение IPC дескриптора для этой
очереди. При этом существуют те
же способы создания и доступа, что и для разделяемой памяти или семафоров.
Реализация примитивов send и receive. Системные вызовы msgsnd() и msgrcv().
Тип данных struct
msgbuf
не является типом данных для пользовательских сообщений, а представляет
собой лишь шаблон для создания таких типов. Пользователь сам должен
создать структуру для своих сообщений, в которой первым полем обязана
быть переменная типа long, содержащая
положительное значение типа сообщения.
В качестве третьего параметра - длины сообщения - указывается
не вся длина структуры данных, соответствующей сообщению, а только длина
полезной информации, т. е. информации, располагающейся в структуре
данных после типа сообщения. Это значение может быть и равным 0 в случае,
когда вся полезная информация заключается в самом факте наличия сообщения
(сообщение используется как сигнальное средство связи).
На наших занятиях мы, как правило, будем использовать
нулевое значение флага системного вызова, которое приводит к блокировке
процесса при отсутствии достаточного свободного места в очереди сообщений.
Для выполнения примитива
send служит системный вызов msgsnd(),
копирующий пользовательское сообщение в очередь сообщений, заданную своим
IPC дескриптором. При изучении описания этого вызова обратите особое внимание
на следующие моменты:
Примитив receive
реализуется системным вызовом msgrcv().
При изучении
описания этого вызова обратите особое внимание на следующие моменты:
Тип данных struct msgbuf, как и для вызова msgsnd(), является лишь шаблоном для пользовательского типа данных.
Способ выбора сообщения задается нулевым, положительным или отрицательным значением параметра type. Точное значение типа выбранного сообщения можно определить из соответствующего поля структуры, в которую системный вызов скопирует сообщение.
Системный вызов возвращает длину только полезной части скопированной информации, т. е. информации, расположенной в структуре после поля типа сообщения.
Выбранное сообщение удаляется из очереди сообщений.
В качестве параметра length указывается максимальная длина полезной части информации, которая может быть размещена в структуре, адресованной параметром ptr.
На наших занятиях мы будем, как правило, пользоваться нулевым значением флагов для системного вызова, которое приводит к блокировке процесса в случае отсутствия в очереди сообщений с запрошенным типом и к ошибочной ситуации в случае, когда длина информативной части выбранного сообщения превышает длину, специфицированную в параметре length.
Максимально возможная длина
информативной части сообщения в операционной системе Linux составляет 4080
байт и может быть уменьшена при генерации системы. Текущее значение максимальной
длины можно определить с помощью команды
ipcs -l
Удаление очереди сообщений из системы с помощью команды ipcrm или системного
вызова msgctl().
После завершения процессов,
использовавших очередь сообщений, она не удаляется из системы автоматически,
а продолжает сохраняться в системе вместе со всеми невостребованными сообщениями
до тех пор, пока
не будет выполнена специальная команда или специальный системный вызов. Для
удаления очереди сообщений можно воспользоваться уже знакомой нам командой
ipcrm, которая в этом случае примет вид:
ipcrm
msg <IPC идентификатор>
Прогон примера с однонаправленной передачей текстовой информации
Для
иллюстрации всего вышесказанного давайте рассмотрим простые программы
/ftp/pub/sem9/09-1a.c и /ftp/pub/sem9/stud/09-1b.c. Первая
из этих программ посылает пять текстовых сообщений с типом 1 и одно
сообщение нулевой длины с типом 255 второй
программе. Вторая программа в цикле
принимает сообщения любого типа в порядке FIFO и печатает их содержимое
до тех пор, пока не получит сообщение с типом 255. Сообщение с типом 255
служит для нее сигналом к завершению работы и ликвидации очереди сообщений.
Если перед запуском любой из программ очередь сообщений еще отсутствовала
в системе, то программа создаст ее.
Обратите внимание на использование сообщения с типом 255 в качестве сигнала
прекращения работы второго процесса. Это сообщение имеет нулевую длину,
так как его информативность исчерпывается самим фактом наличия сообщения.
Модификация предыдущего примера для передачи числовой информации.
В описании системных вызовов msgsnd()
и msgrcv() говорится о том, что передаваемая
информации не обязательно должна представлять собой текст. Мы можем воспользоваться
очередями сообщений для передачи данных любого вида. При передаче разнородной
информации целесообразно информативную часть объединять внутри сообщения
в отдельную структуру:
struct {
float finfo;
для
правильного вычисления длины информативной части. В некоторых вычислительных
системах числовые данные размещаются в памяти с выравниванием на определенные
адреса (например, на адреса кратные 4). Поэтому реальный размер памяти,
необходимой для размещения нескольких числовых данных, может оказаться больше
суммы длин этих данных, т. е. в нашем случае, вообще говоря, sizeof(info)>=sizeof(short)+sizeof(float).
Для полной передачи информативной части сообщения в качестве длины нужно
указывать не сумму длин полей, а полную длину структуры. Модифицируйте предыдущие
программы для передачи нетекстовых сообщений.
Написание, компиляция и прогон программ для осуществления двусторонней связи
через одну очередь сообщений.
Наличие у сообщений типов позволяет организовать двустороннюю связь
между процессами через одну и ту же очередь сообщений. Процесс 1 может посылать
процессу 2 сообщения с типом 1, а получать от него сообщения с типом 2.
При этом для выборки сообщений в обоих процессах следует пользоваться
вторым способом выбора. Напишите, откомпилируйте и прогоните программы,
осуществляющие двустороннюю связь через одну очередь сообщений.
Понятие мультиплексирования. Мультиплексирование сообщений. Модель взаимодействия процессов клиент-сервер. Неравноправность клиента
и сервера.
Используя
технику из предыдущего примера, мы можем организовать получение сообщений
одним процессом от множества других процессов через одну очередь сообщений
и отправку им ответов через ту же очередь сообщений, т.е. осуществить мультиплексирование
сообщений. Вообще под мультиплексированием информации понимают возможность
одновременного обмена информацией с несколькими партнерами. Метод мультиплексирования
широко применяется в модели взаимодействия процессов клиент-сервер.
В этой модели один из процессов является сервером. Сервер получает запросы
от других процессов - клиентов - на выполнение некоторых действий и отправляет
им результаты обработки запросов. Наиболее часто модель клиент-сервер используется
при разработке сетевых приложений, с которыми мы столкнемся на завершающих
семинарах курса. Она изначально предполагает неравноправность взаимодействующих
процессов:
Сервер, как правило, работает постоянно, на всем протяжении жизни приложения, а клиенты могут работать эпизодически.
Сервер ждет запроса от клиентов, инициатором же взаимодействия выступает клиент.
Как правило, клиент обращается к одному серверу за раз, в то время как к серверу могут одновременно поступить запросы от нескольких клиентов.
Клиент должен знать, как обратиться к серверу (например, какого типа сообщения он воспринимает) перед началом организации запроса к серверу, в то время как сервер может получить недостающую информацию о клиенте из пришедшего запроса.
Рассмотрим следующую схему мультиплексирования сообщений через одну очередь сообщений для модели клиент-сервер. Пусть сервер получает из очереди сообщений только сообщения с типом 1. В состав сообщений с типом 1, посылаемых серверу, процессы-клиенты включают значение своих идентификаторов процесса. Приняв сообщение с типом 1, сервер анализирует его содержание, выявляет идентификатор процесса, пославшего запрос, и отвечает клиенту, посылая сообщение с типом равным идентификатору запрашивавшего процесса. Процесс-клиент после посылки запроса ожидает ответа в виде сообщения с типом равным своему идентификатору. Поскольку идентификаторы процессов в системе различны, и ни один пользовательский процесс не может иметь PID равный 1, все сообщения могут быть прочитаны только теми процессами, которым они адресованы. Если обработка запроса занимает продолжительное время, сервер может организовывать параллельную обработку запросов, порождая для каждого запроса новый процесс-ребенок или новую нить исполнения.
Написание, компиляция и прогон программ клиент и сервер.
Напишите, откомпилируйте и прогоните программы сервера и клиентов для предложенной схемы мультиплексирования сообщений.
Использование очередей сообщений для синхронизации работы процессов.
На
лекции была доказана эквивалентность очередей сообщения и семафоров в системах,
где процессы могут использовать разделяемую память. Там, в частности, было
показано, как реализовать семафоры с помощью очередей сообщений. Для этого
вводился специальный синхронизирующий процесс-сервер, обслуживающий переменные-счетчики
для каждого семафора. Процессы-клиенты для выполнения операции над семафором
посылали процессу-серверу запросы на выполнение операции и ожидали ответа
для продолжения работы. Теперь мы знаем, как это можно сделать в операционной
системе UNIX и как, следовательно, можно использовать очереди сообщений
для организации взаимоисключений и взаимной синхронизации процессов.
Задача
повышенной сложности: реализуйте семафоры через очереди сообщений.
Предыдущий семинар | Программа курса | Следующий семинар