Главная » 2017 » Ноябрь » 16 » man 7 aio
23:56
man 7 aio

SEO sprint - Всё для максимальной раскрутки!





ИМЯ


aio - введение в асинхронный ввод-вывод POSIX



ОПИСАНИЕ


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

Интерфейс POSIX AIO состоит из следующих функций:

aio_read(3) Ставит запрос на чтение в очередь. Это асинхронный аналог read(2).

aio_write(3) Ставит запрос на запись в очередь. Это асинхронный аналог
write(2).

aio_fsync(3) Ставит запрос синхронизации операций ввода-вывода над файловым
дескриптором. Это асинхронный аналог fsync(2) и fdatasync(2).

aio_error(3) Возвращает информацию о состоянии поставленного в очередь запроса
ввода-вывода.

aio_return(3) Возвращает информацию о выполненном запросе ввода-вывода.

aio_suspend(3) Приостанавливает вызывающего до тех пор, пока не выполнится один
или более указанных запросов ввода-вывода.

aio_cancel(3) Пытается отменить ожидающие выполнения запросы ввода-вывода над
заданным файловым дескриптором.

lio_listio(3) Ставит в очередь сразу несколько запросов ввода-вывода за один
вызов функции.

В структуре aiocb («блок управления асинхронным вводом-выводом») задаются
параметры, которые управляют операцией ввода-вывода. Аргумент данного типа
передаётся во все функции, перечисленные ранее. Данная структура имеет следующий
вид:

#include <aiocb.h>

struct aiocb {
/* Порядок данных полей определяется реализацией */

int aio_fildes; /* файловый дескриптор */
off_t aio_offset; /* файловое смещение */
volatile void *aio_buf; /* расположение буфера */
size_t aio_nbytes; /* длина передачи */
int aio_reqprio; /* приоритет запроса */
struct sigevent aio_sigevent; /* метод уведомления */
int aio_lio_opcode; /* выполняемая операция;
только в lio_listio() */

/* Не показаны различные поля, используемые в реализациях */
};

/* Коды операций для 'aio_lio_opcode': */
ввода-вывода.

aio_buf Буфер, используемый для пересылки данных при операции чтения или
записи.

aio_nbytes Размер буфера, на который указывает aio_buf.

aio_reqprio В этом поле задаётся значение, которое вычитается из приоритета
реального времени вызывающей нити, чтобы определить приоритет
выполнения данного запроса ввода-вывода (смотрите
pthread_setschedparam(3)). Указываемое значение должно быть в
диапазоне от 0 и до значения, возвращаемого
sysconf(_SC_AIO_PRIO_DELTA_MAX). Данное поле игнорируется при
операциях синхронизации файла.

aio_sigevent В этом поле задаётся структура, которая указывает как вызывающему
должно быть сообщено о завершении анонимной операции ввода-вывода.
Возможные значения для aio_sigevent.sigev_notify: SIGEV_NONE,
SIGEV_SIGNAL и SIGEV_THREAD. Подробности смотрите в sigevent(7).

aio_lio_opcode Задаёт тип операции, которая будет выполнена; используется только
в lio_listio(3).

В дополнении к стандартным функциям, перечисленным ранее, в библиотеке GNU C есть
следующее расширение программного интерфейса POSIX AIO:

aio_init(3) Позволяет изменить настройки поведения реализации glibc для POSIX
AIO.



ОШИБКИ


EINVAL Значение поля aio_reqprio структуры aiocb меньше 0 или больше, чем значение
ограничения, возвращаемое вызовом sysconf(_SC_AIO_PRIO_DELTA_MAX).



ВЕРСИИ


Интерфейсы POSIX AIO появились в glibc в версии 2.1.



СООТВЕТСТВИЕ СТАНДАРТАМ


POSIX.1-2001, POSIX.1-2008.



ЗАМЕЧАНИЯ


Желательно обнулять буфер блока управления перед использованием (смотрите
memset(3)). Буфер блока управления и буфер, который задаётся в aio_buf, не должны
изменяться во время выполнения операции ввода-вывода. Данные буферы должны
оставаться рабочими до завершения операции ввода-вывода.

Одновременное выполнение операций чтения или записи через совместно используемую
структуру aiocb приводит к непредсказуемым результатам.

Имеющаяся реализация Linux POSIX AIO предоставляется glibc в пользовательском
пространстве. Она имеет ряд ограничений, наиболее существенные из которых —
затраты на сопровождение нескольких нитей при операциях ввода-вывода и плохое
масштабирование. Некогда для реализации асинхронного ввода-вывода велась работа
над ядерной реализацией на основе машины состояний (смотрите io_submit(2),
io_setup(2), io_cancel(2), io_destroy(2), io_getevents(2)), но эта реализация ещё
недостаточно стабильна в тех местах, где POSIX AIO можно было бы полностью
реализовать на системных вызовах ядра.

Сигнал SIGQUIT (генерируемый нажатием control-\) заставляет программу отменить все
невыполненные запросы с помощью aio_cancel(3).

Вот результат работы программы. В этом примере программа ставит в очередь два
запроса для стандартного ввода, и они отрабатываются двумя введёнными строками
«abc» и «x».

$ ./a.out /dev/stdin /dev/stdin
opened /dev/stdin on descriptor 3
opened /dev/stdin on descriptor 4
aio_error():
for request 0 (descriptor 3): In progress
for request 1 (descriptor 4): In progress
abc
I/O completion signal received
aio_error():
for request 0 (descriptor 3): I/O succeeded
for request 1 (descriptor 4): In progress
aio_error():
for request 1 (descriptor 4): In progress
x
I/O completion signal received
aio_error():
for request 1 (descriptor 4): I/O succeeded
All I/O requests completed
aio_return():
for request 0 (descriptor 3): 4
for request 1 (descriptor 4): 2

Исходный код программы

#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <aio.h>
#include <signal.h>

#define BUF_SIZE 20 /* размер буферов для операций чтения */

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define errMsg(msg) do { perror(msg); } while (0)

struct ioRequest { /* определяемая приложением структура для
слежения за запросами ввода-вывода */
int reqNum;
int status;
struct aiocb *aiocbp;
};

static volatile sig_atomic_t gotSIGQUIT = 0;
/* при получении SIGQUIT мы пытаемся отменить
все невыполненные запросы ввода-вывода */

static void /* обработчик SIGQUIT */
aioSigHandler(int sig, siginfo_t *si, void *ucontext)
{
if (si->si_code == SI_ASYNCIO) {
write(STDOUT_FILENO, "Получен сигнал завершения ввода-вывода\n", 31);

/* соответствующая структура ioRequest была бы доступна как
struct ioRequest *ioReq = si->si_value.sival_ptr;
а файловый дескриптор был бы доступен через
ioReq->aiocbp->aio_fildes */
}
}

int
main(int argc, char *argv[])
{
struct ioRequest *ioList;
struct aiocb *aiocbList;
struct sigaction sa;
int s, j;
int numReqs; /* общее количество устанавливаемых в очередь
запросов ввода-вывода */
int openReqs; /* количество выполняющихся запросов
ввода-вывода */

if (argc < 2) {
fprintf(stderr, "Использование: %s <имя_файла> <имя_файла>...\n",
argv[0]);
exit(EXIT_FAILURE);
}

numReqs = argc - 1;

/* выделяем место под массивы */

ioList = calloc(numReqs, sizeof(struct ioRequest));
if (ioList == NULL)
errExit("calloc");

aiocbList = calloc(numReqs, sizeof(struct aiocb));
if (aiocbList == NULL)
errExit("calloc");

/* указываем обработчики SIGQUIT и сигнала завершения ввода-вывода */

sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);

sa.sa_handler = quitHandler;
if (sigaction(SIGQUIT, &sa, NULL) == -1)
errExit("sigaction");

sa.sa_flags = SA_RESTART | SA_SIGINFO;
sa.sa_sigaction = aioSigHandler;
if (sigaction(IO_SIGNAL, &sa, NULL) == -1)
errExit("sigaction");

/* открываем каждый файл, заданный в командной строке и ставим в
errExit("open");
printf("opened %s on descriptor %d\n", argv[j + 1],
ioList[j].aiocbp->aio_fildes);

ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE);
if (ioList[j].aiocbp->aio_buf == NULL)
errExit("malloc");

ioList[j].aiocbp->aio_nbytes = BUF_SIZE;
ioList[j].aiocbp->aio_reqprio = 0;
ioList[j].aiocbp->aio_offset = 0;
ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL;
ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr =
&ioList[j];

s = aio_read(ioList[j].aiocbp);
if (s == -1)
errExit("aio_read");
}

openReqs = numReqs;

/* цикл, отслеживание состояние запросов ввода-вывода */

while (openReqs > 0) {
sleep(3); /* задержка между проверками */

if (gotSIGQUIT) {

/* при получении SIGQUIT пытаемся отменить каждый
невыполненный запрос ввода-вывода и показываем состояние,
возвращаемое при отмене запроса */

printf("got SIGQUIT; canceling I/O requests: \n");

for (j = 0; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" Request %d on descriptor %d:", j,
ioList[j].aiocbp->aio_fildes);
s = aio_cancel(ioList[j].aiocbp->aio_fildes,
ioList[j].aiocbp);
if (s == AIO_CANCELED)
printf("I/O canceled\n");
else if (s == AIO_NOTCANCELED)
printf("I/O not canceled\n");
else if (s == AIO_ALLDONE)
printf("I/O all done\n");
else
errMsg("aio_cancel");
}
}

gotSIGQUIT = 0;
}

/* проверяем состояние каждого запроса ввода-вывода, которые
switch (ioList[j].status) {
case 0:
printf("I/O succeeded\n");
break;
case EINPROGRESS:
printf("In progress\n");
break;
case ECANCELED:
printf("Canceled\n");
break;
default:
errMsg("aio_error");
break;
}

if (ioList[j].status != EINPROGRESS)
openReqs--;
}
}
}

printf("All I/O requests completed\n");

/* проверяем возвращаемое состояние всех запросов ввода-вывода */

printf("aio_return():\n");
for (j = 0; j < numReqs; j++) {
ssize_t s;

s = aio_return(ioList[j].aiocbp);
printf(" for request %d (descriptor %d): %zd\n",
j, ioList[j].aiocbp->aio_fildes, s);
}

exit(EXIT_SUCCESS);
}



СМОТРИТЕ ТАКЖЕ


io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2), io_submit(2),
aio_cancel(3), aio_error(3), aio_init(3), aio_read(3), aio_return(3),
aio_write(3), lio_listio(3)

«Asynchronous I/O Support in Linux 2.5», Bhattacharya, Pratt, Pulavarty, and
Morgan, Proceedings of the Linux Symposium, 2003,
⟨https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf⟩



Категория: (7) Различные описания, соглашения и прочее | Просмотров: 498 | Добавил: Администратор | Рейтинг: 0.0/0
Всего комментариев: 0
avatar