Механизмы межпроцессных взаимодействий в операционной системе Unix

Сергей Кузнецов, учебные материалы конференции Индустрия Программирования 96, Центр Информационных Технологий

Традиционный подход ОС UNIX - реакция на сложности Multics

Возникшие проблемы

Избыточный набор системных средств, предназначенных для обеспечения возможности взаимодействия и синхронизации процессов, которые не обязательно связаны отношением родства

Пакет средств IPC

Общие свойства всех трех механизмов:

Разделяемая память

shmget создает новый сегмент разделяемой памяти или находит существующий сегмент с тем же ключом

shmat подключает сегмент с указанным дескриптором к виртуальной памяти обращающегося процесса

shmdt отключает от виртуальной памяти ранее подключенный к ней сегмент с указанным виртуальным адресом начала

shmctl служит для управления параметрами, связанными с существующим сегментом

После подключения сегмента разделяемой памяти к виртуальной памяти процесса, он может обращаться к соответствующим элементам памяти с использованием обычных машинных команд чтения и записи

shmid = shmget(key, size, flag);

virtaddr = shmat(id, addr, flags);

shmdt(addr);

shmctl(id, cmd, shsstatbuf);

Семафоры

Обобщение классического механизма семафоров общего вида Диекстры

Целесообразность обобщения сомнительна

Обычно использовался облегченный вариант двоичных семафоров

Известен алгоритм реализации семафоров общего вида на основе двоичных

Семафор в ОС UNIX:

Три системных вызова:

id = semget(key, count, flag);

oldval = semop(id, oplist, count);

Элемент массива oplist:

Если проверка прав доступа проходит нормально

Значение поля операции положительно

Значение поля операции равно нулю

Значение поля операции отрицательно

(1) его абсолютное значение меньше или равно значению семафора

(2) значение семафора меньше абсолютной величины поля операции

Стремление добиться возможности избегать тупиковых ситуаций

Системный вызов semop выполняется как атомарная операция

Флаг IPC_NOWAIT заставляет ядро ОС UNIX не блокировать текущий процесс

semctl(id, number, cmd, arg);

Можно уничтожить индивидуальный семафор в указанной группе

Очереди сообщений

Четыре системных вызова:

msgqid = msgget(key, flag);

Сообщения хранятся в виде связного списка

Декскриптор очереди сообщений - индекс в массиве заголовков очередей сообщений

В заголовке очереди хранятся:

Структуры данных, используемые для организации очередей сообщений

msgsnd(msgqid, msg, count, flag);

Условия успешной постановки сообщения в очередь:

Процесс продолжает свое выполнение

Ядро активизирует (пробуждает) все процессы, ожидающие поступления сообщений из очереди

Превышается верхний предел суммарной длины сообщений

count = msgrcv(id, msg, maxcount, type, flag);

Значением параметра type является нуль

Значение type есть положительное целое число

Значение type есть отрицательное целое число

В очереди отсутствуют сообщения, соответствующие спецификации type

msgctl(id, cmd, mstatbuf);

Программные каналы

Создание неименованного программного канала

pipe(fdptr);

Создание именованных программных каналов (или получение доступа к существующим)

Обычный системный вызов open

Запись и чтение: read и write

Окончание работы процесса: close

Программные гнезда (sockets)

Поддерживаемый ядром механизм, скрывающий особенности сетевой среды и позволяющий единообразно взаимодействовать процессам

Первое решение:

Три составляющих:

Одна из возможных конфигураций программных гнезд

Допустимые комбинации протоколов и драйверов задаются при конфигурации системы

По духу организация программных гнезд близка к идее потоков

Но менее гибкая схема

Взаимодействие процессов основано на модели "клиент-сервер"

Программные гнезда с общими коммуникационными свойствами, такими как способ именования и протокольный формат адреса, группируются в домены

Два типа программных гнезд

Виртуальные соединения:

Дейтаграммные программные гнезда:

По умолчанию обеспечивается подходящий протокол для каждой допустимой комбинации "домен-гнездо"

Создание нового программного гнезда:

sd = socket(domain, type, protocol);

Закрытие (уничтожение) гнезда

close(sd)

Связывание ранее созданного программного гнезда с именем:

bind(sd, socknm, socknlen);

Запрос связи с существующим программным гнездом со стороны процесса-клиента:

connect(sd, socknm, socknlen);

Информирования о том, что процесс-сервер планирует установление виртуальных соединений через указанное гнездо:

listen(sd, qlength);

Выборка процессом-сервером очередного запроса на установление соединения с указанным программным гнездом служит функция accept:

nsd = accept(sd, address, addrlen);

Передача и прием данных через программные гнезда с установленным виртуальным соединением:

count = send(sd, msg, length, flags);

count = recv(sd, buf, length, flags);

В send:

В recv:

Вместо send и recv можно использовать read и write

Для посылки и приема сообщений в дейтаграммном режиме:

count = sendto(sd, msg, length, flags, socknm, socknlen);

count = recvfrom(sd, buf, length, flags, socknm, socknlen);

Немедленная ликвидация установленного соединения:

shutdown(sd, mode);

shutdown отличаются от close:

Потоки (streams)

UNIX System V

Позволяют организовывать разнообразные виды коммуникации процессов

Многообразие и сложность набора функций библиотеки TLI

Относится к теме реализаций семиуровневой модели ISO/OSI