Главная страница Взаимодействие нетривиальных процессов При вводе команды наподобие who I sort I Ip в интерпретаторе команд Unix интерпретатор выполняет вышеописанные действия для создания трех процессов с двумя каналами между ними. Интерпретатор также подключает открытый для чтения конец каждого канала к стандартному потоку ввода, а открытый на запись - к стандартному потоку вывода. Созданный таким образом канал изображен на рис. 4.5. who процесс sort процесс 1р процесс процесс ядро . поток данных -> -> поток данных -> Рис. 4.5. Каналы между тремя процессами при конвейерной обработке родительский дочерний
процесс ядро
<- поток данных <- Рис. 4.6. Двусторонняя передача данных по двум каналам Все рассмотренные выше каналы были однонаправленными (односторонними), то есть позволяли передавать данные только в одну сторону. При необходимости передачи данных в обе стороны нужно создавать пару каналов и использовать каждый из них для передачи данных в одну сторону. Этапы создания двунаправленного канала IPC следующие: 1. Создаются каналы 1 (fdl[0] и fdl[l]) и 2 (fd2[0] и fd2[l]). 2. Вызов fork. 3. Родительский процесс закрывает доступный для чтения конец канала 1 (f d 1 [ О ]). 4. Родительский процесс закрывает доступный для записи конец канала 2 (f d2 [ 1 ]). 5. Дочерний процесс закрывает доступный для записи конец канала 1 (fdl[l]). 6. Дочерний процесс закрывает доступный для чтения конец канала 2 (fd2[0]). Текст программы, выполняющей эти действия, приведен в листинге 4.1. При этом создается структура каналов, изображенная на рис. 4.6. Пример Давайте напишем программу, описанную в разделе 4.2, с использованием каналов. Функция main создает два канала и вызывает fork для создания копии процесса. Родительский процесс становится клиентом, а дочерний - сервером. Первый канал используется для передачи полного имени от клиента серверу, а второй - для передачи содержимого файла (или сообщения об ошибке) от сервера клиенту. Таким образом мы получаем структуру, изображенную на рис. 4.7. stdin родительский дочерний процесс пут процесс путь- содержимое файла или сообщение itdout об ошибке клиент сервер содержимое файла -(фа или сообщение об ошибке Рис. 4.7. Реализация рис. 4.1 с использованием двух каналов Обратите внимание на то, что мы изображаем на рис. 4.7 два канала, соединяющих сервер с клиентом, но оба канала проходят через ядро, поэтому каждый передаваемый байт пересекает интерфейс ядра дважды: при записи в канал и при считывании из него. В листинге 4.1 приведена функция main для данного примера. Листинг 4.1. Функция main для приложения клиент-сервер, использующего два канала pipe/mainpipe.c 1 #include unpipc.h 2 void clientdnt, int), serverCint, int); 3 int 4 mainCint argc. char **argv) 6 int pipel[2], pipe2[2]; 7 pid t childpid; 8 Pipe(pipel); /* создание двух каналов */ 9 Pipe(pipe2): 10 if ( (childpid - ForkO) =- 0) { /* child */ 11 Close(pipel[l]): 12 Close(pipe2[0]): 13 server(pipel[0], pipe2[l]): родояжение Листинг 4.1 (продолжение) 14 exit(O): 15 } 16 /* родитель */ 17 Close(pipel[0]): 18 Close(pipe2[l]): 19 client(pipe2[0], pipel[l]): 20 WaitpidCchildpid, NULL, 0); /* ожидание завершения дочернего процесса */ 21 exit(O); 22 } Создание каналов, вызов fork 8-19 Создаются два канала и выполняются шесть шагов, уже упоминавшиеся в отношении рис. 4.6. Родительский процесс вызывает функцию с1 lent (листинг 4.2), а дочерний - функцию server (листинг 4.3). Использование waitpid дочерним процессом 20 Процесс-сервер (дочерний процесс) завершает свою работу первым, вызывая функцию exit после завершения записи данных в канал. После этого он становится процессом-зомби. Процессом-зомби называется дочерний процесс, завершивший свою работу, родитель которого еще функционирует, но не получил сигнал о завершении работы дочернего процесса. При завершении работы дочернего процесса ядро посылает его родителю сигнал SIGCHLD, но родитель его не принимает и этот сигнал по умолчанию игнорируется. После этого функция с1 ient родительского процесса возвращает управление функции main, закончив считывание данных из канала. Затем родительский процесс вызывает waitpid для получения информации о статусе дочернего процесса (зомби). Если родительский процесс не вызовет waitpid, а просто завершит работу, клиент будет унаследован процессом init, которому будет послан еще один сигнал SIGCHLD. Функция с1 ient приведена в листинге 4.2. Листинг 4.2. Функция client для приложения типа клиент-сервер с двумя каналами pipe/client.с 1 #include unpipc.h 2 void 3 client(int readfd, int writefd) 5 size t len: 6 ssize t П; 7 char buff[MAXLINE]: 8 /* получение полного имени файла */ 9 FgetsCbuff, MAXLINE, stdin): 10 len = strlen(buff): /* fgetsO гарантирует завершающий нулевой байт */ 11 if (buff[len-l] - Лп) 12 len--: /* удаление перевода строки из fgetsO */ 13 /* запись полного имени в канал IPC */
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |