Процесс блокируется в вызове функции
select
, ожидая, когда дейтаграммный сокет будет готов для чтения. Когда функция
select
возвращает сообщение, что сокет готов для чтения, процесс вызывает функцию
recvfrom
, чтобы скопировать дейтаграмму в буфер приложения.
Сравнивая рис. 6.3 и 6.1, мы не найдем в модели мультиплексирования ввода- вывода каких-либо преимуществ, более того, она даже обладает незначительным недостатком, поскольку использование функции
select
требует двух системных вызовов вместо одного. Но преимущество использования функции
select
, которое мы увидим далее в этой главе, состоит в том, что мы сможем ожидать готовности не одного дескриптора, а нескольких.
Разновидностью данного способа мультиплексирования является многопоточное программирование с блокируемым вводом-выводом. Отличие состоит в том, что вместо вызова select с блокированием программа использует несколько потоков (по одному на каждый дескриптор), которые могут блокироваться в вызовах типа recvfrom.
Модель ввода-вывода, управляемого сигналом
Мы можем сообщить ядру, что необходимо уведомить процесс о готовности дескриптора с помощью сигнала
SIGIO
. Такая модель имеет название
Рис. 6.4. Модель управляемого сигналом ввода-вывода
Сначала мы включаем на сокете управляемый сигналом ввод-вывод (об этом рассказывается в разделе 22.2) и устанавливаем обработчик сигнала при помощи системного вызова
sigaction
. Возвращение из этого системного вызова происходит незамедлительно, и наш процесс продолжается (он не блокирован). Когда дейтаграмма готова для чтения, для нашего процесса генерируется сигнал
SIGIO
. Мы можем либо прочитать дейтаграмму из обработчика сигнала с помощью вызова функции
recvfrom
и затем уведомить главный цикл о том, что данные готовы для обработки (см. раздел 22.3), либо уведомить основной цикл и позволить ему прочитать дейтаграмму.
Независимо от способа обработки сигнала эта модель имеет то преимущество, что во время ожидания дейтаграммы не происходит блокирования. Основной цикл может продолжать выполнение, ожидая уведомления от обработчика сигнала о том, что данные готовы для обработки либо дейтаграмма готова для чтения.
Модель асинхронного ввода-вывода
Рис. 6.5. Модель асинхронного ввода-вывода
Мы вызываем функцию
aio_read
(функции асинхронного ввода-вывода POSIX начинаются с
aio_
или
lio_
) и передаем ядру дескриптор, указатель на буфер, размер буфера (те же три аргумента, что и для функции read), смещение файла (аналогично функции
lseek
), а также указываем, как уведомить нас, когда операция полностью завершится. Этот системный вызов завершается немедленно, и наш процесс не блокируется в ожидании завершения ввода-вывода. В этом примере предполагается, что мы указали ядру сгенерировать некий сигнал, когда операция завершится. Сигнал не генерируется до тех пор, пока данные не скопированы в наш буфер приложения, что отличает эту модель от модели ввода-вывода, управляемого сигналом.
На момент написания книги только некоторые системы поддерживали асинхронный ввод-вывод стандарта POSIX. Например, мы не уверены, что какие-либо системы поддерживают его для сокетов. Мы используем его только как пример для сравнения с моделью управляемого сигналом ввода-вывода.
Сравнение моделей ввода-вывода