Литмир - Электронная Библиотека
Содержание  
A
A

• Процессы QNX сохраняют все качества таковых и в UNIX вообще: они являются изолированными сущностями, которые взаимодействуют, если это необходимо, используя достаточно тяжеловесные (расточительные) механизмы IPC. Собственно, в этом и ценность процессов с их изолированными адресными пространствами — это механизм обеспечения высокой надежности и живучести приложений. Но QNX, не сужая спектр общепринятых IPC-механизмов, привносит совершенно новый «слой» инструментария взаимодействия — обмен сообщениями микроядра. При этом «проницаемость» процессов как отдельных клеток живого организма становится много выше, нисколько не снижая их «защищенности».

Но у нас есть две принципиально различные альтернативы для выражения этого «слоя» взаимодействий в своем программном коде: базовый механизм обмена сообщениями (низкоуровневая техника, известная еще со времен QNX 4.X) и механизм менеджера ресурса. Делать выбор между ними приходится на этапе раннего эскизного проектирования системы, поскольку перестраивать систему с одного механизма на другой в ходе развития — достаточно трудоемкий процесс, который может потребовать пересмотра и архитектурных основ развиваемого проекта.

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

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

При рассмотрении базовой для QNX (собственно, для всех микроядерных ОС) техники обмена сообщениями в сравнении с технологией написания менеджеров ресурсов не покидает ощущение поразительной схожести происходящих в обоих случаях процессов. В этом нет ничего удивительного, поскольку инструментарий менеджеров ресурсов — это только система внешних «оберток» над базовым механизмом обмена сообщениями.

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

Простота и трудоемкость

Механизм прямого обмена сообщениями крайне просто выражается в программном коде. Когда достигнута полная ясность в значениях адресных параметров обмена, необходимо всего лишь несколько операторов, чтобы заставить все это «крутиться».

Со стороны сервера, например, это выглядит так:

int chid = ChannelCreate(0);

...

while (true) {

 struct _msg_info info;

 int rcvid = MsgReceive(chid, &bufin, sizeof(bufin), &info);

 if (rcvid < 0) exit(EXIT_FAILURE);

 if (MsgReply(rcvid, EOK, &bufou, sizeof(bufou) < 0) exit(EXIT_FAILURE);

}

Co стороны клиента:

int coid = ConnectAttach(node, pid, chid, _NTO_SIDE_CHANNEL, 0);

if (coid < 0) exit(EXIT_FAILURE);

...

while(...)

 if (MsgSend(coid, &bufou, sizeof(bufou), &bufin, sizeof(bufin)) == -1)

  exit(EXIT_FAILURE);

}

Код для реализации того же обмена, но организованного как менеджер ресурса, будет как минимум в несколько раз объемнее (образцы менеджеров мы уже видели ранее по тексту). Кроме того, по большей части он будет состоять из заполнения полей некоторых внутренних структур, используемых библиотеками менеджера ресурсов или пула потоков. На первый поверхностный взгляд такой код маловразумителен.

С другой стороны, весь достаточно объемный код любогоменеджера ресурса — это очередное повторение одного и того же общего шаблона для написания менеджеров. При некоторых минимальных навыках написание самых замысловатых менеджеров ресурсов становится совершенно рутинным занятием, не превышающим по трудоемкости написание простого обмена сообщениями. Большим подспорьем здесь является наличие в комплекте технической документации QNX огромного (более 80 страниц) раздела, исчерпывающе описывающего технику создания менеджеров ресурсов; по качеству и скрупулезности изложения это одна из лучших частей всей технической документации.

Гибкость и мобильность

При установлении соединения техника простого обмена сообщениями в качестве адресата сообщений (сервера) использует «магическую тройку» (триплет [1]) параметров ND, PID и CHID, где:

• 

ND
— дескриптор сетевого узла, на котором работает интересующая нас программа-сервер (узел, на который надо отсылать сообщение);

• 

PID
— PID процесса этой программы на своем сетевом узле (кому отсылать сообщение);

• 

CHID
— номер канала, который открыла эта программа для приема сообщений данного вида.

В этой адресации, пожалуй, и кроется самая главная причина негибкости механизма обмена сообщениями. Дескриптор сетевого узла

nd
, значение которого, кроме того, способно самопроизвольно изменяться в сети с течением времени, мы можем установить по сетевому имени интересующего нас хоста, используя
netmgr_strtond()
. (Это действие по своей сути избыточное, дополнительный уровень косвенности, так как первичным идентификатором узла для пользователя приложенияявляется его имя, а не дескриптор.)

Гораздо хуже дело обстоит с

pid
и
chid
, особенно для процесса, выполняющегося на удаленном сетевом узле. Не существует в общем виде прямогоспособа установить PID удаленного процесса, а тем более номер канала, который открыл этот процесс для обмена (или вообще не открывал, если мы, например, ошиблись в определении его PID). И тогда на помощь приходят некоторые искусственные приемы, построенные либо на использовании некоторых иерархических (родительский-дочерний) соотношений процессов клиента и сервера, либо на системах совершенно условных договоренностей (произвольных и варьирующихся от случая к случаю).

Р. Кертен [1] отмечает, что существует множество способов нахождения этой адресной триады, и перечисляет некоторые из них:

1. Открыть файл с известным именем и сохранить в нем ND/PID/CHID…

2. Использовать для объявления идентификаторов ND/PID/CHID глобальные переменные программы…

3. Занять часть пространства имен путей и стать администратором ресурсов.

Не вдаваясь в подробный анализ (вы это можете сделать сами), отметим, что 1-й способ — крайне искусственный и негибкий (особенно в сетевой среде), 2-й — крайне ограничен и применим лишь к узкому кругу задач, а 3-й способ подводит нас к применению совсем другой, альтернативной технологии с используемыми ею принципами адресации.

Несколько, безусловно, интересных и заслуживающих внимания вариаций на тему техники обмена сообщениями предлагает В. Зайцев в приложении, которое следует за данной главой.

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

read()
или
devctl()
, на которые менеджер возвращает свой PID и открытый для прямого обмена дополнительный CHID. На этом функции менеджера заканчиваются, а весь информационный обмен далее идет обменом сообщений через указанный канал. Полный текст такого сервера будет показан в примере позже.

89
{"b":"155449","o":1}