Чтение онлайн

на главную - закладки

Жанры

QNX/UNIX: Анатомия параллелизма
Шрифт:

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

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

netmgr_strtond
,
которая преобразует имя узла в его дескриптор.

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

В [4] (глава Дмитрия Алексеева «Утилита on») этот вопрос был достаточно хорошо освещен и было сказано, что для решения проблемы следует перед порождением процесса вызвать функцию

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

Далее, если дочерний процесс запущен на удаленном узле, то вызванная им функция

getppid
в качестве родительского процесса возвращает совсем даже не идентификатор «фактического» родителя, а идентификатор процесса
io-net
, что, может быть, формально и верно, но по существу это издевательство (особенно для «мигрантов» с QNX 4, где они получали идентификатор виртуального канала и обращались с ним как с обычным идентификатором процесса). Итак, для того чтобы порожденный процесс знал свое «отчество», проще всего родителю передать свой идентификатор дочернему процессу при его рождении в параметре списка
argv[]
.

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

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

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

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

netmgr_strtond
, а идентификатор порожденного процесса возвращается функцией
spawn
.
Но вот с дескриптором канала опять появляется риск «не угадать». Кроме того, если родитель породит дочерний процесс и немедленно после этого попытается подсоединиться к каналу, который должен создать этот процесс, то, вероятнее всего, функция
ConnectAttach
вернет -1, поскольку порожденный процесс еще не успеет к тому времени создать канал. Значит, понадобится цикл на N попыток с паузой в ожидании открытия.

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

MsgSend
.

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

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

index
, задаваемое в вызовах функции
ConnectAttach
равным
_NTO_SIDE_CHANNEL
. В примерах из [1], книги, безусловно, основополагающей для любого программиста под QNX 6, для упрощения изложения это значение устанавливается в 0. Однако значение, равное
_NTO_SIDE_CHANNEL
, гарантирует, что возвращаемое функцией значение идентификатора соединения будет взято не из того же пространства, из которого выделяются файловые дескрипторы; в противном случае возникают проблемы, достаточно определенно обрисованные в описании функции
ConnectAttach
, приведенном в технической документации QNX.

Пример кода родительского процесса

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <process.h>

#include <sys/neutrino.h>

#include <sys/netmgr.h>

#include <spawn.h>

#include <errno.h>

#include <unistd.h>

#include <sys/wait.h>

#include <locale.h>

int main(int argc, char **argv) {

int nid; // Дескриптор удаленного узла

int PChanid; // Идентификатор созданного канала

int CChanid; // Идентификатор канала, созданного

// порожденным процессом на удаленном узле

Поделиться:
Популярные книги

Не кровный Брат

Безрукова Елена
Любовные романы:
эро литература
6.83
рейтинг книги
Не кровный Брат

Релокант

Ascold Flow
1. Релокант в другой мир
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Релокант

Гром над Тверью

Машуков Тимур
1. Гром над миром
Фантастика:
боевая фантастика
5.89
рейтинг книги
Гром над Тверью

Ненастоящий герой. Том 1

N&K@
1. Ненастоящий герой
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Ненастоящий герой. Том 1

Попаданка

Ахминеева Нина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка

Беглец

Кораблев Родион
15. Другая сторона
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Беглец

Приручитель женщин-монстров. Том 6

Дорничев Дмитрий
6. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Приручитель женщин-монстров. Том 6

Неудержимый. Книга IX

Боярский Андрей
9. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга IX

Я еще не князь. Книга XIV

Дрейк Сириус
14. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я еще не князь. Книга XIV

Измена. За что ты так со мной

Дали Мила
1. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. За что ты так со мной

Измена. Испорченная свадьба

Данич Дина
Любовные романы:
современные любовные романы
короткие любовные романы
5.00
рейтинг книги
Измена. Испорченная свадьба

Приручитель женщин-монстров. Том 4

Дорничев Дмитрий
4. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Приручитель женщин-монстров. Том 4

Курсант: назад в СССР 9

Дамиров Рафаэль
9. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: назад в СССР 9

Лорд Системы 12

Токсик Саша
12. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Лорд Системы 12