Опубликован: 06.12.2004 | Доступ: свободный | Студентов: 1180 / 143 | Оценка: 4.76 / 4.29 | Длительность: 20:58:00
ISBN: 978-5-9556-0021-5
Лекция 7:

Асинхронный ввод/вывод, рекомендательные интерфейсы

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >

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

Основными операциями асинхронного ввода/вывода являются чтение и запись данных (см. листинг 7.1).

#include <aio.h>
int aio_read (struct aiocb *aiocbp);
int aio_write (struct aiocb *aiocbp);
Листинг 7.1. Описание функций асинхронного чтения и записи.

Функция aio_read() инициирует запрос на чтение aiocbp->aio_nbytes байт из файла, ассоциированного с дескриптором aiocbp->aio_fildes, начиная с абсолютной позиции aiocbp->aio_offset, в буфер с адресом aiocbp->aio_buf. Возврат из функции произойдет тогда, когда запрос будет принят к исполнению или поставлен в очередь ; при этом нормальный результат равен нулю, а значение -1 (в совокупности с errno ) свидетельствует об ошибке (например, исчерпаны ресурсы и запрос не удалось поставить в очередь ).

Функция aio_write() осуществляет соответствующие действия для записи данных. Если для файлового дескриптора aiocbp->aio_fildes установлен флаг O_APPEND, запись будет производиться в конец файла.

Функция lio_listio() (см. листинг 7.2) позволяет за один вызов инициировать ( поставить в очередь ) список запросов на чтение и/или запись данных.

#include <aio.h>
int lio_listio (
    int mode, struct aiocb *restrict const
    listio [restrict], int nent, 
    struct sigevent *restrict sigev);
Листинг 7.2. Описание функции lio_listio().

Элементы массива listio [] специфицируют отдельные запросы. В полях aio_lio_opcode указуемых структур типа aiocb могут располагаться значения LIO_READ ( запрос на чтение), LIO_WRITE ( запрос на запись) или LIO_NOP (пустой запрос ). Остальные элементы указуемых структур интерпретируются в соответствии со смыслом запроса (можно считать, что адреса структур передаются в качестве аргументов функциям aio_read() или aio_write() ). Число элементов в массиве listio [] задается аргументом nent.

Значение аргумента mode определяет способ обработки списка запросовсинхронный ( LIO_WAIT ) или асинхронный ( LIO_NOWAIT ). В первом случае возврат из вызова lio_listio() произойдет только после завершения всех заказанных операций ввода/вывода ; при этом аргумент sigev игнорируется. Во втором случае возврат из lio_listio() произойдет немедленно, а по завершении всех операций ввода/вывода в соответствии со значением аргумента sigev будет сгенерировано асинхронное уведомление .

Нормальный результат выполнения функции lio_listio() равен нулю, но для двух описанных случаев он имеет разный смысл – успешное завершение всех операций ввода/вывода или только успешная постановка запросов в очередь соответственно. Во втором случае часть операций ввода/вывода может завершиться неудачей, и с каждой из них придется разбираться индивидуально. Подобное разбирательство позволяют осуществить функции aio_return() и aio_error() (см. листинг 7.3).

#include <aio.h>

ssize_t aio_return (
    struct aiocb *aiocbp);

int aio_error (
    const struct aiocb *aiocbp);
Листинг 7.3. Описание функций aio_return() и aio_error().

Аргументом этих функций служит адрес управляющего блока, который играет в данном случае роль идентификатора запроса. Функция aio_return() выдает значение, которое вернула бы соответствующая функция обычного ввода/вывода (если операция ввода/вывода в момент опроса не была завершена, возвращаемое значение, разумеется, не определено). К идентификатору данного запроса функцию aio_return() можно применить ровно один раз; последующие вызовы aio_return() и aio_error() могут завершиться неудачей. (Конечно, если в той же указуемой структуре типа aiocb сформировать новый запрос и выполнить его, возможность корректного вызова функций aio_return() и aio_error() появляется снова.)

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

Ожидающие обработки запросы на асинхронный ввод/вывод можно аннулировать, воспользовавшись функцией aio_cancel() (см. листинг 7.4).

#include <aio.h>
int aio_cancel (int fildes,
                struct aiocb *aiocbp);
Листинг 7.4. Описание функции aio_cancel().

Функция aio_cancel() пытается аннулировать один (если значение аргумента aiocbp отлично от NULL ) или все ожидающие обработки запросы, в которых фигурирует файловый дескриптор fildes. После аннулирования генерируется соответствующее асинхронное уведомление, статус ошибки устанавливается равным ECANCELED, а в качестве возвращаемого значения выдается -1.

Если запрос не удается аннулировать (возможные причины этого, вообще говоря, зависят от реализации), он выполняется стандартным образом.

Результат вызова aio_cancel() равен AIO_CANCELED, если все указанные запросы аннулированы. Если хотя бы один из запросов уже выполняется, он не может быть аннулирован, и тогда в качестве результата возвращается значение AIO_NOTCANCELED (а со статусом запросов, как и для функции lio_listio(), нужно разбираться индивидуально, пользуясь функцией aio_error() ). Результат AIO_ALLDONE свидетельствует о том, что выполнение всех указанных запросов не только начато, но и уже завершено. Во всех остальных случаях результат вызова aio_cancel() равен -1.

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >