Неблокирующий ввод/вывод действительно усложняет вашу жизнь, в этом нет никакого сомнения. Но для многих приложений он является необходимостью, позволяющей выполнить задание. Снова рассмотрите спулер печати. Демон спулера не может позволить себе находиться в блокирующем read()
9.4.3.5. Сводка fcntl()
Сводка для системного вызова fcntl()
Таблица 9.5
. Сводкаfcntl()
Значение cmd | Значение arg | Возвращает |
---|---|---|
F_DUPFD | Наименьший новый дескриптор | Дублирует аргумент fd |
F_GETFD | Получает флаги дескриптора файла (close-on-exec) | |
F_SETFD | Новое значение флага | Устанавливает флаги дескриптора файла (close-on-exec) |
F_GETFL | Получает флаги основного файла | |
F_SETFL | Новое значение флага | Устанавливает флаги основного файла |
Флаги создания, статуса и прав доступа файла копируются, когда дескриптор файла дублируется. Флаг close-on-exec не копируется.
9.5. Пример: двусторонние каналы в gawk
ksh
) ввела двусторонние каналы на уровне языка, обозначив термином print -p "команда базы данных" /* Записать в сопроцесс */
read -p db_response /* Прочесть из сопроцесса */
Здесь
ksh
. У Рис. 9.7
. Сопроцессы оболочки КорнаВ обычном awk
awk
(gawk
) заимствует обозначение '|&
' от ksh
для расширения языка awk
:print "
"
gawk
|&
' также для сокетов TCP/IP и порталов BSD, которые не рассматриваются в данной книге. Следующий код из io.c
в дистрибутиве gawk
3.1.3 является частью функции two_way_open()
, которая устанавливает простой сопроцесс: она создает два канала, порождает новый процесс и осуществляет все манипуляции с дескриптором файла. Мы опустили ряд не относящихся к делу частей кода (эта функция занимает больше места, чем следовало бы):1561 static int
1562 two_way_open(const char *str, struct redirect *rp)
1563 {
...
1827 /* случай 3: двусторонний канал с порожденным процессом */
1828 {
1829 int ptoc[2], сtop[2];
1830 int pid;
1831 int save_errno;
1835
1836 if (pipe(ptoc) < 0)
1837 return FALSE; /* установлен errno, диагностика от вызывающего */
1838
1839 if (pipe(ctop) < 0) {
1840 save_errno = errno;
1841 close(ptoc[0]);
1842 close(ptoc[1]);
1843 errno = save_errno;
1844 return FALSE;
1845 }
Первым шагом является создание двух каналов, ptoc
ctop
— «от потомка к родителю». Во время чтения держите в уме, что индекс 0 является читаемым концом, а 1 — записываемым.