Рис. 6.5. Модель асинхронного ввода-вывода
Мы вызываем функцию aio_read
(функции асинхронного ввода-вывода POSIX начинаются с aio_
или lio_
) и передаем ядру дескриптор, указатель на буфер, размер буфера (те же три аргумента, что и для функции read), смещение файла (аналогично функции lseek
), а также указываем, как уведомить нас, когда операция полностью завершится. Этот системный вызов завершается немедленно, и наш процесс не блокируется в ожидании завершения ввода-вывода. В этом примере предполагается, что мы указали ядру сгенерировать некий сигнал, когда операция завершится. Сигнал не генерируется до тех пор, пока данные не скопированы в наш буфер приложения, что отличает эту модель от модели ввода-вывода, управляемого сигналом.
ПРИМЕЧАНИЕ
На момент написания книги только некоторые системы поддерживали асинхронный ввод-вывод стандарта POSIX. Например, мы не уверены, что какие-либо системы поддерживают его для сокетов. Мы используем его только как пример для сравнения с моделью управляемого сигналом ввода-вывода.
Сравнение моделей ввода-вывода
На рис. 6.6 сравнивается пять различных моделей ввода-вывода. Здесь видно главное отличие четырех первых моделей в первой фазе, поскольку вторая фаза у них одна и та же: процесс блокируется в вызове функции recvfrom
на то время, пока данные копируются из ядра в буфер вызывающего процесса. Асинхронный ввод-вывод отличается от первых четырех моделей в обеих фазах.
Рис. 6.6. Сравнение моделей ввода-вывода
Сравнение синхронного и асинхронного ввода-вывода
POSIX дает следующие определения этих терминов:
■ Операция синхронного ввода-вывода блокирует запрашивающий процесс до тех пор, пока операция ввода-вывода не завершится.
■ Операция асинхронного ввода-вывода не вызывает блокирования запрашивающего процесса.
Используя эти определения, можно сказать, что первые четыре модели ввода- вывода — блокируемая, неблокируемая, модель мультиплексирования ввода-вывода и модель управляемого сигналом ввода-вывода — являются синхронными, поскольку фактическая операция ввода-вывода (функция recvfrom
) блокирует процесс. Только модель асинхронного ввода-вывода соответствует определению асинхронного ввода-вывода.
Эта функция позволяет процессу сообщить ядру, что необходимо подождать, пока не произойдет одно из некоторого множества событий, и вывести процесс из состояния ожидания, только когда произойдет одно или несколько таких событий или когда пройдет заданное количество времени.
Например, мы можем вызвать функцию select
и сообщить ядру, что возвращать управление нужно только когда наступит любое из следующих событий:
■ любой дескриптор из набора {1, 4, 5} готов для чтения;
■ любой дескриптор из набора {2, 7} готов для записи;
■ любой дескриптор из набора {1, 4} вызывает исключение, требующее обработки;
■ истекает 10,2 с.
Таким образом, мы сообщаем ядру, какие дескрипторы нас интересуют (готовые для чтения, готовые для записи или требующие обработки исключения) и как долго нужно ждать. Интересующие нас дескрипторы не ограничиваются сокетами: любой дескриптор можно проверить с помощью функции select
.
ПРИМЕЧАНИЕ
Беркли-реализации всегда допускали мультиплексирование ввода-вывода с любыми дескрипторами. Система SVR3 ограничивала мультиплексирование ввода-вывода дескрипторами, которые являлись устройствами STREAMS (см. главу 31), но это ограничение было снято в SVR4.
#include
#include
int select(int maxfdp1 , fd_set * readset , fd_set * writeset ,
fd_set * exceptset , const struct timeval * timeout );
Возвращает: положительное число - счетчик готовых дескрипторов, 0 в случае тайм-аута, -1 в случае ошибки
Описание этой функции мы начнем с последнего аргумента, который сообщает ядру, сколько следует ждать, пока один из заданных дескрипторов не будет готов. Структура timeval
задает число секунд и микросекунд:
struct timeval {
long tv_sec; /* секунды */
long tv_usec; /* микросекунды */
};
С помощью этого аргумента можно реализовать три сценария:
Читать дальше
Конец ознакомительного отрывка
Купить книгу