Неблокирующий ввод/вывод действительно усложняет вашу жизнь, в этом нет никакого сомнения. Но для многих приложений он является необходимостью, позволяющей выполнить задание. Снова рассмотрите спулер печати. Демон спулера не может позволить себе находиться в блокирующем read() для файла FIFO, которому представлены входящие задания. Он должен иметь также возможность отслеживать запущенные задания и, возможно, периодически проверять состояние печатающих устройств (например, убедиться, что не заело бумагу).

<p>9.4.3.5. Сводка fcntl()</p>

Сводка для системного вызова fcntl() приведена в табл. 9.5.

Таблица 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 не копируется.

<p>9.5. Пример: двусторонние каналы в <code>gawk</code></p>

Двусторонний канал соединяет два процесса двунаправленным образом. Обычно, по крайней мере для одного из процессов, на канал с другим процессом настраиваются как стандартный ввод, так и стандартный вывод. Оболочка Корна (ksh) ввела двусторонние каналы на уровне языка, обозначив термином сопроцесса (coprocess):

команды и аргументы движка базы данных |& /* Запустить сопроцесс в фоновом режиме */

print -p "команда базы данных" /* Записать в сопроцесс */

read -p db_response /* Прочесть из сопроцесса */

Здесь движок базы данных представляет любую серверную программу, которая может управляться интерфейсной частью, в данном случае, сценарием ksh. У движка базы данных стандартный ввод и стандартный вывод подсоединены к оболочке посредством двух отдельных односторонних каналов.[102] Это показано на рис. 9.7.

Рис. 9.7. Сопроцессы оболочки Корна

В обычном awk каналы к или от подпроцесса являются односторонними: нет способа послать данные в программу и прочесть посланные от нее в ответ данные — нужно использовать временный файл. GNU awk (gawk) заимствует обозначение '|&' от ksh для расширения языка awk:

print "команда" |& "движок базы данных" /* Запустить сопроцесс, записать в него */

"движок базы данных" |& getline db_response /* Прочесть из сопроцесса */

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 — записываемым.

Перейти на страницу:

Похожие книги