Главная страница Взаимодействие нетривиальных процессов При записи в программный канал или канал FIFO вызовом wri te данные всегда добавляются к уже имеющимся, а вызов read считывает данные, помещенные в программный канал или FIFO первыми. При вызове функции Iseek для программного канала или FIFO будет возвращена ошибка ESPIPE. Пример Переделаем программу, приведенную в листинге 4.1, таким образом, чтобы использовать два канала FIFO вместо двух программных каналов. Функции с1 lent и server останутся прежними; отличия появятся только в функции main, новый текст которой приведен в листинге 4.6. Листинг 4.6. Функция main приложения клиент-сервер, использующего две очереди pipe/mainfifo.c 1 #include unpipc.h 2 #define FIFOl /tmp/fifo.l 3 #define FIF02 /tmp/fifo.2 4 void clientCint. int). serverCint. int); 5 int 6 mainCint argc. char **argv) 8 int readfd. writefd: 9 pid t childpid; 10 /* создание двух FIFO, если существуют - OK */ 11 if CCmkfifoCFIFOl. FILE MODE) < 0) && Cerrno !- EEXIST)) 12 err sysC cant create *s . FIFOl): 13 if CCmkfifoCFIF02. FILE MODE) < 0) && Cerrno != EEXIST)) { 14 unlinkCFIFOl): 15 err sysC cant create *s . FIF02); 16 } 17 if С Cchildpid = ForkO) - 0) { /* child */ 18 readfd - OpenCFIFOl, 0 RDONLY, 0); 19 writefd - OpenCFIF02. 0 WRONLY. 0); 20 serverCreadfd. writefd): 21 exitCO): 22 } 23 /* родительский процесс */ 24 writefd - OpenCFIFOl. 0 WRONLY. 0): 25 readfd - OpenCFIF02. 0 RDONLY. 0): 26 clientСreadfd, writefd): 27 WaitpidCchildpid. NULL. 0): /* ожидание завершения дочернего процесса */ 28 CIoseCreadfd): 29 CloseCwritefd): 30 UnlinkCFIFOl): продолжение ё>- Листинг 4.6 (продолжение) 31 Unlink(FIF02): 32 exit(O): 33 } Создание двух FIFO 10-16 В файловой системе в каталоге /tmp создается два канала. Если какой-либо из них уже существует - ничего страшного. Константа FILE MODE определена в нашем заголовке unpi рс. h (листинг В.1) как fdefine FILE MODE (S IRUSR S IWUSR S IRGRP S IROTH) /* разрешения по умолчанию для вновь создаваемых файлов */ При этом владельцу файла разрешается чтение и запись в него, а группе и прочим пользователям - только чтение. Эти биты разрешений накладываются на маску режима доступа создаваемых файлов (file mode creation mask) процесса. 17-27 Далее происходит вызов fork, дочерний процесс вызывает функцию server (листинг 4.3), а родительский процесс вызывает функцию client (листинг4.2). Перед вызовом этих функций родительский процесс открывает первый канал на запись, а второй на чтение, в то время как дочерний процесс открывает первый канал на чтение, а второй - на запись. Картина аналогична примеру с каналами и иллюстрируется рис. 4.11. родительский процесс дочерний процесс
<- поток данных <- Рис. 4.11. Приложение клиент-сервер, использующее две очереди Изменения по сравнению с примером, в которым использовались программные каналы, следующие: ш Для создания и открытия программного канала требуется только один вызов - pipe. Для создания и открытия FIFO требуется вызов mkfifo и последующий вызов open. Ш Программный канал автоматически исчезает после того, как будет закрыт последним использующим его процессом. Канал FIFO удаляется из файловой системы только после вызова unl i nk. Польза от лишнего вызова, необходимого для создания FIFO, следующая: канал FIFO получает имя в файловой системе, что позволяет одному процессу со- здать такой канал, а другому открыть его, даже если последний не является родственным первому. С программными каналами это неосуществимо. В программах, некорректно использующих каналы FIFO, могут возникать неочевидные проблемы. Рассмотрим, например, листинг 4.6: если поменять порядок двух вызовов функции open в породившем процессе, программа перестанет работать. Причина в том, что чтение из FIFO блокирует процесс, если канал еще не открыт на запись каким-либо другим процессом. Действительно, если мы меняем порядок вызовов open в породившем процессе, и породивший, и порожденный процессы открывают канал на чтение, притом что на запись он еще не открыт, так что оба процесса блокируются. Такая ситуация называется блокированием, или зависанием (deadlock). Она будет рассмотрена подробно в следующем разделе. Пример: неродственные клиент и сервер в листинге 4.6 клиент и сервер все еще являлись родственными процессами. Переделаем этот пример так, чтобы родство между ними отсутствовало. В листинге 4.7 приведен текст программы-сервера. Текст практически идентичен той части программы из листинга 4.6, которая относилась к серверу. Содержимое заголовка f i fо. h приведено в листинге 4.8. Этот файл определяет имена двух FIFO, которые должны быть известны как клиенту, так и серверу. В листинге 4.9 приведен текст программы-клиента, которая не слишком отличается от части программы из листинга 4.6, относящейся к клиенту. Обратите внимание, что именно клиент, а не сервер удаляет канал FIFO по завершении работы, потому что последние операции с этим каналом выполняются им. Листинг 4.7. Функция main независимого сервера pipe/server niain.c 1 #include fifo.h 2 void serverCint. int): 3 int 4 mainCint argc. char **argv) 6 int readfd. writefd: 7 /* создание двух FIFO. OK. если они существуют */ 8 if CCmkfifoCFIFOl. FILE MOOE) < 0) && Cerrno !- EEXIST)) 9 err sysC cant create *s . FIFOl): 10 if CCmkfifoCFIF02. FILE MODE) < 0) && Cerrno !- EEXIST)) { 11 unlinkCFIFOl); 12 err sysC cant create *s . FIF02): 13 } 14 readfd = OpenCFIFOl. 0 RDONLY. 0): 15 writefd - OpenCFIF02. 0 WRONLY. 0): 16 serverCreadfd. writefd): 17 exitCO): 18 )
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |