Friday, May 18th

Last update12:13:00 PM GMT

Вы находитесь на: FreeBSD Обзор системы ввода/вывода Мультиплексирование ввода/вывода для дескрипторов

Мультиплексирование ввода/вывода для дескрипторов

Иногда процессу нужно обработать ввод/вывод для более чем одного дескриптора. Например, рассмотрите программу удаленной регистрации, которая хочет прочесть данные с клавиатуры и послать их через сокет на удаленную машину. Эта программа хочет также прочесть данные из сокета, подключенного к удаленной машине, и вывести их на экран. Если процесс делает запрос чтения, когда нет доступных данных, он обычно блокируется в ядре до тех пор, пока данные не станут доступны. В нашем примере блокирование неприемлемо. Если процесс читает из клавиатуры и блокируется, он будет не способен прочесть данные от удаленной машины, которые предназначены для вывода на экран. Пользователь не знает, что набрать, до тех пор, пока не поступят дополнительные данные с удаленного конца, поэтому сеанс попадает в тупик. И наоборот, если процесс читает с удаленного конца, когда нет данных для экрана, он будет заблокирован и не сможет ничего прочесть с терминала. Опять возник бы тупик, если на удаленном конце ожидали вывода до отправки каких-либо данных. Есть аналогичный набор проблем блокирования записей на экран или на удаленном конце. Если пользователь остановил вывод на свой экран, набрав символ остановки, запись будет заблокирована до тех пор, пока пользователь не введет символ запуска. Между тем процесс не может читать с клавиатуры, чтобы выяснить, что пользователь хочет сбросить вывод.

FreeBSD предусматривает три механизма, которые позволяют мультиплексировать ввод/вывод для дескриптора: опрос ввода/вывода, неблокирующий ввод/вывод и управляемый сигналами ввод/вывод. Опрос осуществляется посредством системных вызовов select или poll. Операции для неблокирующих дескрипторов завершаются немедленно, частично завершают операцию ввода или вывода и возвращают частичный результат или же ошибку, указывающую, что операция вовсе не может быть завершена. Дескрипторы с включенной сигнализацией вызывают уведомление соответствующего процесса или группы процесса, когда состояние ввода/вывода дескриптора изменяется.

Есть четыре возможные альтернативы, позволяющие избежать проблемы блокирования.

1. Установка всех дескрипторов в неблокирующий режим. После этого процесс может пытаться выполнить операцию для каждого из дескрипторов по очереди, чтобы

1. выяснить, какой из них готов к вводу/выводу. Проблема с этим подходом ожидания в ходе работы в том, что процесс должен непрерывно работать, чтобы обнаружить, можно ли выполнить какой-нибудь ввод/вывод, растрачивая циклы процессора впустую.

2. Дать всем представляющим интерес дескрипторам возможность сигнализировать, когда можно выполнить ввод/вывод. Процесс может затем ожидать сигнал, чтобы определить, когда можно делать ввод/вывод. Недостаток этого подхода в том, что перехват сигналов дорог. Поэтому управляемый сигналами ввод/вывод непрактичен для приложений, объем ввода/вывода которых колеблется от умеренного до большого.

3. Заставить систему предоставить метод опроса того, какие дескрипторы могут выполнить ввод/вывод. Если ни один из запрошенных дескрипторов не готов, система может перевести процесс в состояние сна до тех пор, пока дескриптор не будет готов. Эта проблема позволяет избежать проблемы тупика, поскольку процесс будет пробужден каждый раз, когда будет возможен ввод/вывод, и ему будет сообщено, какой дескриптор готов. Недостаток в том, что процесс должен делать два системных вызова на одну операцию: один для опроса готовности дескриптора выполнить ввод/вывод, а другой для выполнения самой операции.

4. Заставить процесс уведомить систему о всех дескрипторах, которые он хочет прочесть, а затем выполнить блокирующее чтение для этого набора дескрипторов. Когда операция чтения возвращается, процесс уведомляется о том, для какого дескриптора было выполнено чтение. Преимуществом этого подхода является то, что процесс выполняет единственный системный вызов для указания набора дескрипторов, а затем выполняет в цикле лишь чтение [Accetta et al., 1986; Lemon, 2001 ].

Первый подход доступен в FreeBSD в виде неблокирующего ввода/вывода. Он обычно используется для вывода в дескрипторы, поскольку эта операция обычно не блокируется. Вместо выполнения select или poll, которые почти всегда завершаются успешно и за которыми сразу же следует write, более эффективно попытаться выполнить write и вернуться к использованию select или poll лишь в те периоды, когда write возвращает ошибку блокирования. Второй подход доступен в FreeBSD в виде управляемого сигналами ввода/вывода. Обычно он используется для редких событий, таких как поступление внеполосных данных сокета. Для таких редких событий стоимость обработки случайного сигнала ниже, чем стоимость постоянной проверки с помощью select или poll, есть ли какие-либо ожидающие данные.

Третий подход доступен в FreeBSD посредством системных вызовов select или poll. Хотя он менее эффективен, чем четвертый подход, это более общий интерфейс. Кроме обработки чтения от нескольких дескрипторов он управляет записью в несколько дескрипторов, уведомлением об исключительных ситуациях и тайм-аутом, когда никакой ввод/вывод невозможен.

Интерфейсы select и poll предоставляют одну и ту же информацию. Они отличаются лишь в своем интерфейсе программирования. Интерфейс select был впервые разработан в 4.2BSD с введением основанного на сокетах межпроцессного взаимодействия. Интерфейс poll был введен в System V несколькими годами позже с их конкурирующим межпроцессным взаимодействием на основе потоков (STREAMS). Хотя потоки STREAMS оказались неиспользуемыми, интерфейс poll оказался достаточно популярным, чтобы остаться. Ядро FreeBSD поддерживает оба интерфейса.

Системный вызов select выглядит так:

Он принимает три маски для отслеживаемых дескрипторов, соответствующие чтению, записи и исключительным условиям. Кроме того, он принимает значение тайм-аута для возвращения из select, если ни один из запрошенных дескрипторов не будет готов, когда истечет указанный промежуток времени. Вызов select возвращает те же самые три маски дескрипторов после их изменения таким образом, чтобы указать, какие дескрипторы могут выполнить чтение, запись или в каких из них возникли исключительные условия. Если ни один из дескрипторов не стал готов за время интервала тайм-аута, select возвращается, указывая, что ни один из дескрипторов не готов для ввода/вывода. Если значение тайм-аута указано и дескриптор становится готовым до истечения указанного периода времени, время, которое select проводит в ожидании ввода/вывода, вычитается из указанного времени.

Интерфейс poll копирует массив структур pollfd, по одному элементу массива для каждого представляющего интерес дескриптора. Структура pollfd содержит три элемента:

· дескриптор файла для опроса;

· набор флагов, описывающих разыскиваемую информацию;

· набор установленных ядром флагов, обозначающих найденную информацию.

Флаги определяют готовность обычных или дополнительных (внеполосных - out-of-band) данных для чтения и доступность буферного пространства для записи обычных или дополнительных (внеполосных) данных. Возвращаемые флаги могут также указывать, что в дескрипторе возникла ошибка, что дескриптор был отсоединен или что дескриптор не открыт. Эти условия ошибок устанавливаются select путем указания, что дескриптор с ошибкой готов к выполнению ввода/вывода. Когда приложение пытается выполнить ввод/вывод, системным вызовом read или write возвращается ошибка. Подобно вызову select, вызов poll принимает значение тайм-аута для указания максимального времени ожидания. Если ни один из запрошенных дескрипторов не становится готовым до истечения указанного промежутка времени, вызов poll возвращается. Если дано время тайм-аута и дескриптор становится готовым до истечения указанного периода времени, время, которое poll провел в ожидании готовности ввода/ вывода, вычитается из указанного времени.


Похожие:
Еще по теме:
Советуем прочитать:

Сейчас 53 гостей онлайн

Реклама на сайте:

Эвакуатор мытищи по материалам auto3o.ru.

рассада в кассетах Растение - Садовод-огородник.