59-60 Механизмы межпроцессорного взаимодействия в QNX. Состояния процессов. Службы синхронизации. Межпроцессорное взаимодействие в сети.
В QXN поддерживаются три механизма межпроцессорного взаимодействия :
1. Сигналы. Необходимы для совместимости с POSIX и обеспечения асинхронного взаимодействия. Сигнал доставляется только разблокированному процессу. Если процесс заблокирован, то сигнал переходит в состояние отложенного. Варианты приема сигналов:
1.) если процессу не предписано выполнять специальные действия по обработке сигнала, то по умолчанию прекращается выполнение процесса;
2.) процесс может игнорировать сигнал (но не любой);
3.) если процесс имеет обработчик сигнала, то при поступлении сигнала ему передаётся управление.
2. Proxy. Форма неблокирующей передачи сообщений, специально предназначенной для оповещения о событиях, при которых процесс-отправитель не нуждается во взаимодействии с получателем. Функция: посылка фиксированного сообщения процессу, создавшему proxy.
Примеры использования proxy:
1.) один процесс оповещает другой процесс о наступлении некоторого события, не желая оставаться SEND-блокированным;
2.) процесс посылает данные другому, но не требует подтверждения о получении сообщения;
3.) обработчик прерываний оповещает процесс о том, что некоторые данные доступны для обработки.
3. Сообщения. Обеспечивают синхронное взаимодействие.
Функции : Send(), Receive(), Reply().
Существует два способа передачи сообщения:
1.) Send-управляемая;
2.) Reply-управляемая.
При Send-управляемой передаче сервер (принимающий) блокируется на команде receive(). В таком случае сервер находится в receive-блокированном состоянии.
При Reply-управляемой передаче блокируется клиент (на команде send). В таком случае получаем send-блокированное состояния клиента.
Если же серверу необходимо время на обработку сообщения и он не может сразу послать reply, то клиент получается reply-блокирован.
Пусть теперь клиент был reply-блокирован и к нему приходит сигнал. В таком случае процесс переводится в состояние сигнал-блокированного с задержанным сигналом.
Из сказанного видно, что появляются 4 состояния блокировок:
1.) Send-блокированный;
2.) Receive-блокированный;
3.) Reply-блокированный;
4.) Сигнал-блокированный.
Состояния процессов:
# READY (готов) - процесс может использовать центральный процессор (т. е. он не ждет наступления никакого события);
# BLOCKED (блокирован) - процесс находится в одном из следующих состояний блокировки:
# SEND-блокирован;
# RECEIVE-блокирован;
# REPLY-блокирован;
# SIGNAL-блокирован;
# HELD (задержан) - процесс получил сигнал SIGSTOP. До тех пор, пока он не выйдет из состояния HELD, ему не разрешается использовать центральный процессор. Вывести из состояния HELD можно либо выдачей сигнала SIGCONT, либо завершить процесс по сигналу;
# WAIT- (ожидает) - процесс выдал wait() или waitpid() и ожидает информацию о состоянии порожденных им процессов;
# DEAD (мертв) - процесс завершен, но не может передать информацию о своем состоянии породившему его процессу, поскольку тот не выдал функцию wait() или waitpid(). За завершенным процессом сохраняется состояние, но занимаемая им память освобождается. Процесс в состоянии DEAD также называют "зомби"-процессом.
Межпроцессорное взаимодействие в сети.
Осуществляется посредством виртуальных каналов (аналог RPC). Пусть на узле 1 есть процесс с ID=PID1. На узле 2 есть процесс с ID =PID2. Необходимо организовать между ними взаимодействие. На узле 1 создается виртуальный образ процесса PID2: VID1=Virtual(PID2). Точно также на 2–м узле: VID2=Virtual(PID1).

Далее взаимодействие виртуальных образов (по сети) управляется ядром. Взаимодействие PIDi ó VIDi осуществляется стандартными механизмами.
Если произошел разрыв канала, то администратор процесса выполняет следующие действия:
1.) при успешной передаче обновляется временна метка;
2.) если нет активности, то администратор проверяет работоспособность канала;
3.) если ответ не получен, то предпринимается попытка восстановления;
4.) при неудаче восстановления канал отключается, разрегистрируется и процессы разблокируются с ошибкой.
Передача сообщений в QNX: Send и Reply-управляемая передача сообщений, передача данных и уведомления, условный прием сообщений, чтение сообщения по частям и прием составных сообщений. Сигналы и сообщения.
Для организации передачи сообщений используются функции:
1.) Send – используется отправителем для передачи сообщения.
Send (pid, smsg, rmsg, smsg_len, rmsg_len)
è pid – идентификатор процесса-получателя;
è smsg – буфер посылаемого сообщения;
è rmsg – буфер ответа;
è smsg_len, rmsg_len – размеры буферов.
2.) Receive – используется для получения сообщения.
pid = receive (0, msg, msg_len)
è pid – идентификатор процесса, пославшего сообщение;
è 0 – указывает на то, что процесс готов принять сообщение от любого процесса;
è msg – буфер приема сообщений.
è msg_len – размер принимающего буфера.
3.) Reply – оповещение отправителя об успешном получении
reply (pid, reply, reply_len)
è pid – идентификатор процесса, которому направляется ответ;
è reply – буфер ответа;
è reply_len – длина буфера.

Send-управляемая передача. Обслуживающий процесс находится в receive-блокированном состоянии до тех пор, пока обслуживаемый процесс не пошлет ему сообщение с помощью send.
Reply-управляемая передача. Обслуживаемый процесс посылает сообщение о своей готовности (send) и send-блокируется. После приема сообщения обслуживающим процессом (receive) обслуживаемый процесс переводится в состояние reply-блокированного. В конце концов обслуживающий процесс посылает reply и обслуживаемый процесс может выполнять работу и отослать результаты.
Условный прием сообщений. Во избежание длительной блокировки обслуживающего процесса используется специальная функция условного приема creceive(). Если у процесса есть ожидающее его готовое сообщение, то оно отправляется ему. Если же сообщений нет, управление передается получателю (который вызвал creceive()).
Чтение или запись сообщения по частям. Используется для того, чтобы было возможно использовать буфер, уже выделенный для сообщения, и не заводить рабочий буфер.
Существует возможность считывания заголовка сообщения с целью определения его длины. Если эта длина больше выделенного буфера, то администратор ввода/вывода может вызвать функцию Readmsg() несколько раз, передавая данные по мере освобождения буфера. Аналогично при малом размере внутреннего буфера администратора ввода/вывода можно использовать функцию Writemsg().
Существует возможность передачи составных сообщений. Для эффективной передачи/приема сообщений без копирования во временный буфер каждое сообщение можно разбить на несколько составляющих, каждая из которых хранится в отдельном буфере. Составное сообщение описывается специальной структурой mx:
Функции работы с составными сообщениями:
è Creceivemx()
è Readmggmx()
è Receivemx()
è Replymx()
è Sendmx()
è Writemsgmx()
Сигналы и сообщения.
Если процесс был send или receive-блокированным, то при приходе сообщения выполняются действия:
1.) процесс разблокируется
2.) выполняется обработка сигнала
3.) функции send/receive возвращают управление с кодом ошибки.
Если процесс был reply-блокирован, то после обработки сигнала неизвестно, дошло ли сообщение получателю.
Процесс-сервер может запрашивать уведомления о том, когда клиент выдаст сигнал, находясь в reply-блокированном состоянии. В этом случае клиент переходит в signal-блокированное состояние с задержанным сигналом. Сервер принимает сообщение с типом сигнала и может:
1.) нормально завершить первоначальный запрос: клиент получит reply;
2.) освободить ресурсы и вернуть код ошибки: клиент получит чистый код ошибки.


