Читать книгу 📗 "Linux программирование в примерах - Роббинс Арнольд"
/* Показать тип и права доступа, обратите внимание на 'p' впереди */prw-r--r-- 1 arnold devel 0 Oct 23 15:49 afifo$ <b>cat < afifo &</b> /* Запустить читателя в фоновом режиме */[1] 22100$ <b>echo It was a Blustery Day > afifo</b> /* Послать данные в FIFO */$ It was a Blustery Day /* Приглашение оболочки, cat выводит данные */ /* Нажмите ENTER, чтобы увидеть статус завершения задания */[1]+ Done cat <afifo /* cat завершился */9.4. Управление дескрипторами файлов
На данный момент части загадки почти полностью составлены,
fork()exec()pipe()Системные вызовы
dup()dup2()close()fcntl()9.4.1. Дублирование открытых файлов:
dup()dup2()Два системных вызова создают копию открытого дескриптора файла:
#include <unistd.h> /* POSIX */int dup(int oldfd);int dup2(int oldfd, int newfd);Функции следующие:
int dup(int oldfd)Возвращает наименьшее значение неиспользуемого дескриптора файла; это копия
oldfddup()int dup2(int oldfd, int newfd)Делает
newfdoldfdnewfdclose()dup2()dup()dup2()
Рис. 9.4. Разделение дескриптора файла как результат '
dup2(1, 3)На этом рисунке процесс выполнил '
dup2(1, 3)В разделе 4.4.2 «Открытие и закрытие файлов» мы упомянули, что
open()creat()open()creat()dup2()При наличии правила «возвращения наименьшего неиспользуемого номера» в сочетании с функцией
dup()1. Создать канал с помощью
pipe()2. Создать то, что мы называем «левым потомком». Это процесс, стандартный вывод которого идет в канал. В данном процессе сделать следующее:
a. Использовать '
close(pipefd[0])b. Использовать '
close(1)c. Использовать '
dup(pipefd[1])d. Использовать '
close(pipefd[1])e. Выполнить
exec3. Создать то, что мы называем «правым потомком». Это процесс, стандартный ввод которого поступает из канала. Шаги для этого потомка являются зеркальным отражением шагов для левого потомка:
a. Использовать '
close(pipefd[1])b. Использовать '
close(0)c. Использовать '
dup(pipefd[0])d. Использовать '
close(pipefd[0])e. Выполнить
exec4. В родителе закрыть оба конца канала — '
close(pipefd[0]); close(pipefd[1])5. Наконец, использовать в родителе
wait()Обратите внимание, как важно закрыть неиспользуемые копии дескрипторов файлов каналов. Как мы отмечали ранее, файл не закрывается до тех пор, пока не будет закрыт последний открытый для него дескриптор. Это верно, даже если дескрипторы файлов разделяют несколько процессов. Закрытие не использующихся дескрипторов файлов имеет значение, поскольку процесс, читающий из канала, не получит указания конца файла, пока все копии записываемого конца не будут закрыты.
В нашем случае после порождения двух потомков имеются три процесса, у каждого из которых есть копии двух дескрипторов файлов каналов: родительский и два порожденных. Родительский процесс закрывает оба конца, поскольку ему не нужен канал. Левый потомок записывает в канал, поэтому ему нужно закрыть читаемый конец. Правый потомок читает из канала, поэтому ему нужно закрыть записываемый конец. Это оставляет открытым ровно по одной копии дескриптора файла.