Распечатка 7.12 Копирование файла с помощью асинхронного ввода-вывода |
Предыдущая Содержание Следующая |
Распечатка 7.12.
/* aio_cp.c */
#include <unistd.h> #include <aio.h> #include <sys/types.h> #include <errno.h>
#define INPUT_FILE "./input" #define OUTPUT_FILE "./output" /* Размер для передачи в одной операции чтения или записи */ #define XFER_SIZE 1024 #define MAX 3
/* Функция для заполнения aiocb значениями */ void populate_aiocb(struct aiocb *aio, int fd, off_t offset, int bytes, char *buf){ aio->aio_fildes = fd; aio->aio_offset = offset;
/* * Мы не используем здесь механизм уведомления, чтобы уделить * больше внимания интерфейсам AIO. Для получения уведомления * после завершения AIO мы можем использовать механизмы * уведомления либо SIGEV_SIGNAL, либо SIGEV_THREAD */ aio->aio_sigevent.sigev_notify = SIGEV_NONE; aio->aio_nbytes = bytes; aio->aio_buf = buf; }
/* * Это приложение копирует один файл в другой */ int main(){
/* Файловые дескрипторы чтения/записи */ int fd_r , fd_w; /* Блоки управления AIO для чтения и записи */ struct aiocb a_write, a_read;
/* * Этот список используется для хранения блоков * управления исходящих запросов чтения или записи */ struct aiocb *cblist[MAX]; /* Статус операции чтения или записи */ int err_r, err_w; /* число на самом деле считанных байтов */ int read_n = 0; /* Метка завершения потока для файла-источника */ int quit = 0; /* Используются для передачи данных между источником * и файлом назначения */ char read_buf[XFER_SIZE]; char write_buf[XFER_SIZE];
/* * Открываем файлы источника и места назначения. Вызываем * функцию populate_aiocb, чтобы проинициализировать блоки * управления AIO для операции чтения и записи. Хорошей * практикой является очистка блоков aiocb перед * их использованием */ fd_r = open(INPUT_FILE, O_RDONLY, 0444); fd_w = open(OUTPUT_FILE, O_CREAT | O_WRONLY, 0644);
memset(&a_write, 0 , sizeof(struct aiocb)); memset(&a_read, 0 , sizeof(struct aiocb));
/* Заполняем блоки aiocb значениями по умолчанию */ populate_aiocb(&a_read, fd_r, 0, XFER_SIZE, read_buf); populate_aiocb(&a_write, fd_w, 0, XFER_SIZE, write_buf);
/* * Запускаем асинхронное чтение из файла-источника с помощью * функции aio_read. Эта функция читает a_read.aio_nbytes * байтов из файла a_read.aio_fildes, начиная со смещения * a_read.aio_offset в буфер a_read.aio_buf. В случае успеха * возвращается 0. Эта функция возвращается сразу после * помещения запроса в очередь. */ aio_read(&a_read);
/* * Ожидаем завершения чтения. После старта любой асинхронной * операции (чтения или записи), можно получить её статус с * помощью функции aio_error. Если запрос не завершён, эта * функция возвращает EINPROGRESS, если запрос завершён * успешно, она возвращает 0, в противном случае возвращается * значение ошибки. Если aio_read возвращает EINPROGRESS, вызов * aio_suspend ожидает завершения операции. */ while((err_r = aio_error(&a_read)) == EINPROGRESS){ /* * Функция aio_suspend приостанавливает вызывающий процесс, * пока не завершится по крайней мере один из асинхронных * запросов ввода/вывода в списке cblist, или не будет * доставлен сигнал. Здесь мы ждём завершения aio_read * для блока a_read. */ cblist[0] = &a_read; aio_suspend(cblist, 1, NULL); }
/* * Если возвращаемое значение функции aio_error равно 0, то * операция чтения была успешной. Вызываем aio_return, чтобы * узнать количество прочитанных байтов. Функция должна быть * вызвана только один раз после того, как aio_error * возвращает нечто, отличное от EINPROGRESS. */ if (err_r == 0){ read_n = aio_return(&a_read); if (read_n == XFER_SIZE) /* Смещениями должны управлять мы */ a_read.aio_offset += XFER_SIZE; else { /* * Для простоты предположим, что размер файла-источника * больше, чем XFER_SIZE */ printf(“Source file size < %d\n”, XFER_SIZE); exit(1); } }
/* * В этом цикле мы копируем данные, считанные выше, в буфер * записи и запускаем операцию асинхронной записи. Также, * думаем вперёд и помещаем в очередь запрос на чтение для * следующего цикла. */ while(1){ memcpy(write_buf, read_buf, read_n);
/* * Настраиваем блок управления записи. Чтобы поместить в * очередь запрос на запись вызываем aio_write. Эта функция * запишет a_write.aio_nbytes байтов из буфера * a_write.aio_buf в файл a_write.aio_fildes со смещением * a_write.aio_offset. В случае успеха возвращает 0. */ a_write.aio_nbytes = read_n; aio_write(&a_write);
/* Помещаем в очередь следующий запрос на чтение */ a_read.aio_nbytes = XFER_SIZE; aio_read(&a_read);
/* * Перед началом обработки ожидаем завершения и чтения, * и записи */ while((err_r = aio_error(&a_read)) == EINPROGRESS || (err_w = aio_error(&a_write)) == EINPROGRESS){ cblist[0] = &a_read; cblist[1] = &a_write; aio_suspend(cblist, 2, NULL); }
/* Это конец? */ if (quit) break; /* Увеличиваем на единицу указатель записи */ a_write.aio_offset += aio_return(&a_write); /* Увеличиваем на единицу указатель чтения */ read_n = aio_return(&a_read); if (read_n == XFER_SIZE) a_read.aio_offset += XFER_SIZE; else /* Это последний блок */ quit = 1; } }
/* Очистка */ close(fd_r); close(fd_w); }
|
Предыдущая Содержание Следующая |