KnigaRead.com/

Олег Цилюрик - QNX/UNIX: Анатомия параллелизма

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Олег Цилюрик, "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() и т.д.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*