Олег Цилюрик - QNX/UNIX: Анатомия параллелизма
При подобной иерархической структуре системы по типу «родитель-ребенок» общение между порожденными процессами, если таковое требуется, обеспечивается с помощью родительского процесса. Породив один из процессов и получив от него дескриптор канала, родительский процесс может при порождении еще одного процесса передать ему полную триаду «старшего» дочернего процесса, позволяющую новому процессу установить с ним соединение.
Ниже приводится образец кода, реализующего этот подход. Обратите внимание на значение аргумента 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; // Идентификатор канала, созданного
// порожденным процессом на удаленном узле
int coid; // Идентификатор связи с порожденным
// процессом по созданному им каналу
int rcvid; // Идентификатор отправителя полученного
// сообщения int
ErrCode; // Код ошибки
char *args[] = {
"/net/904-3/home/ZZZ/BIN/TestChild",
"pid данного процесса",
"идентификатор канала",
NULL
};
char BufName[100], Bufpid[12],
Bufchanid[12], RecBuffer[100];
char SendBuf[100] = "привет, сынок!";
pid_t procid, childid;
struct inheritance Inhproc;
setlocale(LC_CTYPE, "C-TRADITIONAL");
if ((PChanid = ChannelCreate(0)) == -1)
printf("Родитель: странно, но не удалось "
"создать каналn");
else printf("Родитель: канал PChanid = %i созданn", PChanid);
strcpy(BufName, "Bed-Test");
// Передаем порожденному процессу свой pid...
args[1] = itoa(procid = getpid(), Bufpid, 10);
// ... и дескриптор канала
args[2] = itoa(PChanid, Bufchanid, 10);
InhProc flags = SPAWN_SETND | SPAWN_NOZOMBIE;
if ((nid = netmgr_strtond(BufName, NULL)) == -1) {
printf("Родитель, отсутствует %sn", BufName);
return(-1);
} else printf("Родитель: найден узел %s, его nid = %in", BufName, nid);
InhProc nd = nid;
sprintf(BufName, "/net/Bed-Test/");
chroot(BufName);
errno = 0;
childid = spawn(args[0], 0, NULL, &InhProc, args, NULL);
ErrCode = errno;
sprintf(BufName, "/net/904-3/");
chroot(BufName);
if (childid- = -1)
printf("Родитель: не удалось породить процесс,"
" errno = %in", ErrCode);
else
printf("Родитель, мой id = %i,"
"порожденный процесс имеет id = %in", procid, childid);
if ((rcvid = MsgReceive(PChanid, RecBuffer, 100, NULL)) == -1)
printf("Родитель: от дитятки не удалось"
" получить сообщениеn");
else {
printf("Родитель: от дитятки получено"
" сообщение:"%s"n", RecBuffer);
CChanid = atoi(RecBuffer);
strcpy(RecBuffer, "спасибо, сынок");
if (MsgReply(rcvid, EOK, RecBuffer, 100) == -1)
printf("Родитель: почему-то не удалось "
"ответить сыночку: Ау, где ты?n");
}
if ((coid =
ConnectAttach(nid, childid, CChanid, _NTO_SIDE_CHANNEL, 0)) == -1) {
printf("Родитель: странно, но не смог установить"
" канал связи с ребенком:"
"nid = %i childid = %i CChanid = %in", nid, childid, CChanid);
return(-1);
}
printf("Родитель: установил связь coid = %i с"
" ребенкомn", coid);
errno = 0;
if (MsgSend(coid, SendBuf, 100, SendBuf, 100) == -1)
printf("Родитель: на MsgSend получил errno = %in", errno);
else
printf("Родитель, получен отклик на MsgSend()"
", "%s"n", SendBuf);
printf("Родитель: позвольте откланятьсяn");
ChannelDestroy(Pchanid);
ConnectDetach(CChanid);
return(0);
}
Пример кода порожденного процесса
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <process.h>
#include <sys/netmgr.h>
#include <sys/neutrino.h>
#include <errno.h>
#include <locale.h>
int main(int argc, char **argv) {
int nid; // Дескриптор текущего узла
int CChanid; // Идентификатор созданного канала
int coid; // Идентификатор связи с родителем
// по созданному им каналу
pid_t Parpid; // Идентификатор родительского процесса
int rcvid; // Идентификатор отправителя
// полученного сообщения
char BufName[100];
char SendBuf[100], RecBuf[100];
setlocale(LC_CTYPE, "C-TRADITIONAL");
if ((CChanid = ChannelCreate(0)) == -1)
printf("Ребенок: странно, но не удалось создать"
" каналn");
else
printf("Ребенок: канал CChanid = %i созданn", CChanid);
Parpid = atoi(argv[1]);
printf("Ребенок сообщает: он жив благодаря папане"
" Parpid = %in", Parpid);
strcpy(BufName, "904-3");
if ((nid = netmgr_strtond(BufName, NULL)) == -1)
printf("Ребенок: узел "%s" не найден!n", BufName);
else
printf("Ребенок: узел "%s" найден, его nid = %in", BufName, nid);
if ((coid =
ConnectAttach(nid, Parpid, atoi(argv[2]), _NTO_SIDE_CHANNEL, 0)) == -1) {
printf("Ребенок: странно, но дитя не смогло"
" установить канал связи с папанейn");
return(-1);
}
printf("Ребенок: установил связь coid = %i с процессом"
" Parpid = %i на узле %in", coid, Parpid, nid);
// Вот здесь хорошее место, чтобы выполнить все действия,
// необходимые для развертывания данного процесса
itoa(CChanid, SendBuf, 10);
errno = 0;
if (MsgSend(coid, SendBuf, 100, SendBuf, 100) == -1)
printf("Ребенок: на MsgSend() к отцу получил"
" errno = %in", errno);
else
printf("Ребенок: на MsgSend() получен отклик"
" от родителя."%s"n", SendBuf);
rcvid = MsgReceive(CChanid, RecBuf, 100, NULL);
printf("Ребенок: от папани получено сообщение:"
" "%s"n", RecBuf);
strcpy(RecBuf, "я здесь, папаня!");
if (MsgReply(rcvid, EOK, RecBuf, 100) == -1)
printf("Ребенок: почему-то не удалось ответить"
" папаше. Ау, где ты?n");
printf("Ребенок: дитятко работу закончилоn");
ChannelDestroy(CChanid);
ConnectDetach(coid);
return(0);
}
Обмен сообщениями на основе менеджера ресурсов
Описанный выше способ построения функционирующей в сети системы процессов может быть реализован далеко не всегда. Зачастую клиенту не известна полная триада, позволяющая ему создать соединение с сервером. Вспомним, что в QNX 4, где для создания связи с другим процессом был необходим его идентификатор, существовала служба пространства имен, обеспечиваемая сервером службы nameloc. Сервер объявлял свое имя в пространстве имен с помощью функции qnx_name_attach(), а затем клиент, вызвав функцию qnx_name_locate(), получал от системы идентификатор сервера, по которому мог далее с ним общаться.
Разработчики QNX 6 настоятельно рекомендуют вместо использования службы имен выполнять сервер в виде менеджера ресурсов, причем настолько настоятельно, что до версии 6.3 аналог этой службы — менеджер службы глобальных имен gns — функционировал только локально. И надо признать, что мощь и изящество менеджера ресурсов являются очень убедительным подкреплением этих рекомендаций.
При использовании механизма менеджера ресурсов процесс, выступающий в качестве сервера, регистрирует свой так называемый префикс путевого имени файла в пространстве файловых имен, после чего другие процессы (клиенты) могут открывать это имя как файл, используя стандартную библиотечную функцию open(). Получив в результате выполнения этой функции дескриптор файла, они затем могут обращаться к серверу, используя стандартные библиотечные функции С, такие как read(), write() и т.д.
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Олег Цилюрик - QNX/UNIX: Анатомия параллелизма, относящееся к жанру Программное обеспечение. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.


