10.3.4 Опрос терминала

10.3.4 Опрос терминала

Иногда удобно производить опрос устройства, то есть считывать с него данные, если они есть, или продолжать выполнять обычную работу — в противном случае. Программа на Рисунке 10.18 иллюстрирует этот случай: после открытия терминала с параметром "no delay" (без задержки) процессы, ведущие чтение с него, не приостановят свое выполнение в случае отсутствия данных, а вернут управление немедленно (см. алгоритм terminal_read, Рисунок 10.15). Этот метод работает также, если процесс следит за множеством устройств: он может открыть каждое устройство с параметром "no delay" и опросить всех из них, ожидая поступления информации с каждого. Однако, этот метод растрачивает вычислительные мощности системы.

#include ‹fcntl.h›

main() {

 register int i, n;

 int fd;

 char buf[256];

 /* открытие терминала только для чтения с опцией "no delay" */

 if ((fd = open("/dev/tty", O_RDONLYO_NDELAY)) == -1) exit();

 n = 1;

 for(;;) {  /* всегда */

  for (i = 0; i ‹ n; i++);

  if (read(fd, buf, sizeof(buf)) › 0) {

   printf("чтение с номера %d ", n);

   n--;

  }

  else n++; /* ничего не прочитано; возврат вследствие "no delay" */

 }

}

Рисунок 10.18. Опрос терминала

В системе BSD есть системная функция select, позволяющая производить опрос устройства. Синтаксис вызова этой функции:

select(nfds, rfds, wfds, efds, timeout)

где nfds — количество выбираемых дескрипторов файлов, а rfds, wfds и efds указывают на двоичные маски, которыми "выбирают" дескрипторы открытых файлов. То есть, бит 1 ‹‹ fd (сдвиг на 1 разряд влево значения дескриптора файла) соответствует установке на тот случай, если пользователю нужно выбрать этот дескриптор файла. Параметр timeout (тайм-аут) указывает, на какое время следует приостановить выполнение функции select, ожидая поступления данных, например; если данные поступают для любых дескрипторов и тайм-аут не закончился, select возвращает управление, указывая в двоичных масках, какие дескрипторы были выбраны. Например, если пользователь пожелал приостановиться до момента получения данных по дескрипторам 0, 1 или 2, параметр rfds укажет на двоичную маску 7; когда select возвратит управление, двоичная маска будет заменена маской, указывающей, по каким из дескрипторов имеются готовые данные. Двоичная маска wfds выполняет похожую функцию в отношении записи дескрипторов, а двоичная маска efds указывает на существование исключительных условий, связанных с конкретными дескрипторами, что бывает полезно при работе в сети.