Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [ 17 ] 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

При вводе команды наподобие

who I sort I Ip

в интерпретаторе команд Unix интерпретатор выполняет вышеописанные действия для создания трех процессов с двумя каналами между ними. Интерпретатор также подключает открытый для чтения конец каждого канала к стандартному потоку ввода, а открытый на запись - к стандартному потоку вывода. Созданный таким образом канал изображен на рис. 4.5.

who процесс

sort процесс

1р процесс


процесс ядро

. поток данных -> -> поток данных ->

Рис. 4.5. Каналы между тремя процессами при конвейерной обработке

родительский

дочерний


процесс

процесс

fd1[1]

fd2[0]

fd2[1]

fd1[0]

процесс ядро

-►

канал 1

-> поток данных

->

канал 2

<- поток данных <- Рис. 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 */



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [ 17 ] 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.