Системное программирование в UNIX средствами Free Pascal

       

Запись и чтение без блокирования


Как уже было упомянуто, при использовании и вызова fdread, и вызова fdwrite может возникнуть блокирование, которое иногда нежелательно. Может, например, понадобиться, чтобы программа выполняла процедуру обработки ошибок или опрашивала несколько каналов до тех пор, пока не получит данные из одного из них. К счастью, есть простые способы пресечения нежелательных остановов внутри fdread и fdwrite.

Первый метод заключается в использовании для вызова fstat. Поле size в возвращаемой вызовом структуре tstat сообщает текущее число символов, находящихся в канале. Если только один процесс выполняет чтение из канала, такой подход работает прекрасно. Если же несколько процессов выполняют чтение из канала, то за время, прошедшее между вызовами fstat и fdread, ситуация может измениться, если другой процесс успеет выполнить чтение из канала.

Второй метод заключается в использовании вызова

fcntl. Помимо других выполняемых им функций этот вызов позволяет процессу устанавливать для дескриптора файла флаг Open_NONBLOCK. Это предотвращает блокировку последующих вызовов fdread или fdwrite. В этом контексте вызов fcntl может использоваться следующим образом:

uses linux;

.

.

.

fcntl(filedes, F_SETFL, Open_NONBLOCK);

if linuxerror <> 0 then

  perror('fcntl');

Если дескриптор filedes является открытым только на запись, то следующие вызовы fdwrite не будут блокироваться при заполнении канала. Вместо этого они будут немедленно возвращать значение -1 и присваивать переменной linuxerror значение Sys_EAGAIN. Аналогично, если дескриптор filedes соответствует выходу канала, то процесс немедленно вернет значение -1, если в канале нет данных, а не приостановит работу. Так же, как и в случае вызова fdwrite, переменной linuxerror будет присвоено значение Sys_EAGAIN. (Если установлен другой флаг – Open_NDELAY, то поведение вызова fdread будет другим. Если канал пуст, то вызов вернет нулевое значение. Далее этот случай не будет рассматриваться.)

Следующая программа иллюстрирует применение вызова fcntl. В ней создается канал, для дескриптора чтения из канала устанавливается флаг Open_NONBLOCK, а затем выполняется вызов fork. Дочерний процесс посылает сообщения родительскому, выполняющему бесконечный цикл, опрашивая канал и проверяя, поступили ли данные.



Содержание раздела