7.3.8 Асинхронный ввод-вывод

Предыдущая  Содержание  Следующая V*D*V

Традиционные системные вызовы чтения и записи являются блокирующими вызовами. Большинство приложений реального времени может нуждаться в прерывании их работы и процесса ввода/вывода с целью улучшения детерминизма. Например, приложение может предпочесть асинхронный ввод/вывод (Asynchronous I/O, AIO), если требуется сбор большого объёма данных от какого-то источника и если обработка данных - интенсивное вычисление. POSIX.1b определяет асинхронные интерфейсы ввода/вывода для выполнения требований таких приложений.

Механизм очень прост. Приложение может поместить в очередь запрос на AIO, а затем продолжить нормальную обработку. По завершении ввода/вывода приложение уведомляется. Затем оно может запросить состояние ввода/вывода, чтобы узнать был ли он успешным или закончился неудачей. Используя интерфейсы AIO, приложение может выполнять следующие операции:

 

Формировать нескольких неблокирующих запросов ввода/вывода для различных источников с помощью единственного вызова. (Таким образом, приложение может иметь много операций ввода/вывода в процессе выполнения, в то время как оно выполняет другой код.)

Отменять любые не выполненные запросы ввода/вывода.

Ожидать завершения ввода/вывода.

Отслеживать состояние ввода/вывода: в процессе работы, ошибка, или завершён.

 

Блок управления асинхронным вводом-выводом

 

Блок управления AIO, структура aiocb, является ядром AIO POSIX.1b. Эта структура содержит сведения, которые необходимы для представления AIO. Структура определяется следующим образом:

 

struct aiocb

{

  int aio_fildes;              /* Файловый дескриптор. */

  int aio_lio_opcode;          /* Операция для выполнения,

                                  чтение или запись. Используется

                                  при нескольких запросах AIO

                                  в одном запросе */

  int aio_reqprio;              /* Изменение приоритета запроса. */

  volatile void *aio_buf;       /* Расположение буфера для чтения

                                   или записи */

  size_t aio_nbytes;            /* Размер передачи. */

  struct sigevent aio_sigevent; /* Информация уведомления. */

  off_t aio_offset;             /* Смещение в файле для начала

                                   чтения или записи в него */

}

 

Обратите внимание, что в отличие от традиционных операций чтения или записи, вам необходимо указать смещение в файле, откуда должен начаться AIO. После выполнения ввода/вывода ядро не будет увеличивать значение поля, содержащее смещение в файле, в файловом дескрипторе. Вы должны следить за смещениями в файле вручную.

 

Функции асинхронного ввода-вывода

 

Функции AIO приведены в Таблице 7.11. Использование интерфейсов AIO POSIX.1b иллюстрирует Распечатка 7.12. Этот пример просто копирует один файл в другой с помощью AIO. Для простоты будем считать, что функции AIO не возвращают ошибку.

 

Таблица 7.11 Функции асинхронного ввода-вывода

 

Метод

Описание

aio_read

Старт асинхронного чтения.

aio_write

Старт асинхронной записи.

aio_error

Возвращает статус завершения последней aio_read или aio_write.

aio_return

Возвращает число байт, переданных в aio_read или aio_write.

aio_cancel

Отменяет любые ожидающие операции AIO.

aio_suspend

Вызывает процесс, если завершается любой из указанных запросов.

lio_listio

Запрос нескольких операций чтения или записи.

 

Ввод/вывод, направляемый в список

 

Для передачи произвольного числа запросов чтения или записи в одном вызове может быть использована функция lio_listio:

 

int lio_listio(int mode, struct aiocb *list[], int nent,

               struct sigevent *sig);

 

mode: этот аргумент может быть LIO_WAIT или LIO_NOWAIT. Если этот аргумент имеет значение LIO_WAIT, функция ждёт, пока все вводы-выводы завершатся и sig игнорируется. Если аргументом является LIO_NOWAIT, функция возвращается немедленно и после завершения ввода/вывода будет происходить асинхронное уведомление, как указано в sig.

Список aiocb: этот аргумент содержит список aiocb.

nent: количество aiocb во втором аргументе.

sig: желаемый механизм уведомления. Уведомление не генерируется, если этот аргумент NULL.

 

Распечатка 7.12 может быть изменена для использования функции lio_listio.

 

while(1){

  memcpy(write_buf, read_buf, read_n);

  a_write.aio_nbytes = read_n;

  a_read.aio_nbytes = XFER_SIZE;

 

  /* Готовим список aiocb для lio_listio */

  cblist_lio[0] = &a_read;

  cblist_lio[1] = &a_write;

 

  /*

   * Вызываем lio_listio, чтобы отправить запросы

   * асинхронного чтения и записи

   */

  lio_listio(LIO_NOWAIT, cblist_lio, 2, NULL);

        ……………

}

 

Реализация в Linux

 

Первоначально AIO в Linux был полностью реализован в пользовательском пространстве с помощью потоков. Был один пользовательский поток, создаваемый для каждого запроса. Это привело к плохой масштабируемости и низкой производительности. Начиная с версии 2.5, в ядро была добавлена поддержка AIO. Тем не менее, интерфейсы ядра, предоставляющие AIO, отличаются от интерфейсов POSIX. Интерфейсы базируются на новом наборе системных вызовов. Они перечислены в Таблице 7.12. Эти интерфейсы предоставляются в пользовательском пространстве библиотекой libaio.

 

Таблица 7.12 Интерфейсы асинхронного ввода-вывода в ядре

 

Метод

Описание

io_setup

Создание нового контекста запросов для AIO.

io_submit

Отправка запроса AIO

(также известна как aio_read, aio_write, lio_listio).

io_getevents

Узнать о завершённых операциях ввода/вывода

(также известна как aio_error, aio_return).

io_wait

Ожидание завершения ввода/вывода (также известна как aio_suspend).

io_cancel

Отмена I/O (также известна как aio_cancel).

io_destroy

Уничтожение контекста AIO. Происходит по умолчанию при завершении процесса.

 

Что следует помнить

 

Блок управления не должен изменяться во время выполнения операции чтения или записи. Также, указатель буфера в aiocb должен быть действителен, пока запрос не завершен.

Возвращаемое значение lio_listio не указывает состояние отдельных запросов ввода/вывода. Неудачное завершение запроса не препятствует завершению других запросов.

 

Предыдущая  Содержание  Следующая