Описание функций асинхронного чтения
#include <aio.h> int aio_read (struct aiocb *aiocbp); int aio_write (struct aiocb *aiocbp); |
Листинг 7.1. Описание функций асинхронного чтения и записи. |
Закрыть окно |
#include <aio.h> int lio_listio ( int mode, struct aiocb *restrict const listio [restrict], int nent, struct sigevent *restrict sigev); |
Листинг 7.2. Описание функции lio_listio(). |
Закрыть окно |
#include <aio.h> ssize_t aio_return ( struct aiocb *aiocbp); int aio_error ( const struct aiocb *aiocbp); |
Листинг 7.3. Описание функций aio_return() и aio_error(). |
Закрыть окно |
#include <aio.h> int aio_cancel ( int fildes, struct aiocb *aiocbp); |
Листинг 7.4. Описание функции aio_cancel(). |
Закрыть окно |
#include <aio.h> int aio_suspend ( const struct aiocb *const listio [], int nent, const struct timespec *timeout); |
Листинг 7.5. Описание функции aio_suspend(). |
Закрыть окно |
#include <unistd.h> void sync (void); #include <unistd.h> int fsync (int fildes); #include <unistd.h> int fdatasync (int fildes); #include <aio.h> int aio_fsync ( int op, struct aiocb *aiocbp); |
Листинг 7.6. Описание функций синхронизации оперативной и долговременной памяти. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * */ /* Программа подсчитывает суммарное */ /* число строк – в файлах аргументах */ /* командной строки. */ /* Если аргументы отсутствуют или в */ /* качестве имени задан минус, */ /* читается стандартный ввод. */ /* * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <aio.h> #include <assert.h> #include <errno.h> int main (int argc, char *argv []) { /* Указатель на массив */ /* указателей на управляющие */ /* блоки запросов операций */ /* асинхронного чтения */ struct aiocb **lio_ptr; // Общее число строк в файлах long nlines = 0; // Признак повторного указания // стандартного ввода int dup_stdin = 0; int i; /* Сведем случай с отсутствием */ /* аргументов к общему, */ /* воспользовавшись одним из */ /* немногих стандартизованных */ /* файлов */ if (argc == 1) { argv [0] = "-"; } else { argv [0] = "/dev/null"; } /* Зарезервируем память, */ /* откроем заданные файлы */ /* и сформируем начальный список */ /* запросов на чтение */ assert ((lio_ptr = (struct aiocb **) malloc (sizeof (struct aiocb *) * argc)) != NULL); for (i = 0; i < argc; i++) { assert ((lio_ptr [i] = (struct aiocb *) malloc (sizeof (struct aiocb))) != NULL); if (strcmp (argv [i], "-") == 0) { if (dup_stdin == 0) { lio_ptr [i]->aio_fildes = STDIN_FILENO; dup_stdin = 1; } else { lio_ptr [i]->aio_fildes = fcntl (STDIN_FILENO, F_DUPFD, 0); } } else if ((lio_ptr [i]->aio_fildes = open (argv [i], O_RDONLY)) == -1) { perror ("OPEN"); free (lio_ptr [i]); lio_ptr [i] = NULL; continue; } lio_ptr [i]->aio_offset = 0; assert ((lio_ptr [i]->aio_buf = malloc(BUFSIZ)) != NULL); lio_ptr [i]->aio_nbytes = BUFSIZ; lio_ptr [i]->aio_reqprio = 0; lio_ptr [i]->aio_sigevent.sigev_notify = SIGEV_NONE; lio_ptr [i]->aio_lio_opcode = LIO_READ; } /* for (i < argc) */ /* Поехали ... */ assert (lio_listio (LIO_NOWAIT, lio_ptr, argc, &lio_ptr [0]->aio_sigevent) == 0); /* Будем ждать завершения */ /* операций ввода/вывода, */ /* обрабатывать прочитанные */ /* данные и */ /* инициировать новые запросы */ /* на чтение */ while (aio_suspend (( const struct aiocb **) lio_ptr, argc, NULL) == 0) { /* Выясним, какой запрос */ /* и как выполнен */ /* Число недочитанных файлов */ int nreqs = 0; for (i = 0; i < argc; i++) { if (lio_ptr [i] == NULL) { continue; } /* Есть обслуживаемые */ /* запросы */ nreqs++; if (aio_error (lio_ptr [i]) == EINPROGRESS) { continue; } { // Запрос выполнен // Число прочитанных байт ssize_t nb; if ((nb = aio_return (lio_ptr [i])) <= 0) { /* Дошли до конца файла*/ /* или чтение */ /* завершилось ошибкой */ (void) close(lio_ptr [i]->aio_fildes); free ((void *) lio_ptr [i]->aio_buf); free (lio_ptr [i]); lio_ptr [i] = NULL; nreqs--; } else { /* Обработаем прочитанные */ /* данные */ /* Текущее начало поиска */ /* перевода строки */ char *p; /* Позиция, где нашли */ /* перевод строки */ char *p1; p = (char *) lio_ptr [i]->aio_buf; while ((p1 = (char *) memchr (p, '\n', nb - (p – (char *) lio_ptr [i]->aio_buf))) != NULL) { nlines++; p = p1 + 1; } /* Инициируем новый */ /* запрос на чтение */ lio_ptr [i]->aio_offset += nb; (void) aio_read (lio_ptr [i]); } } } /* for (i < argc) */ /* Остались недочитанные */ /* файлы? */ if (nreqs == 0) { break; } } /* while */ printf ("%ld\n", nlines); return 0; } |
Листинг 7.7. Пример программы, использующей функции асинхронного ввода/вывода. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа подсчитывает суммарное число строк */ /* в файлах – аргументах командной строки. */ /* Если аргументы отсутствуют или в качестве имени */ /* задан минус, читается стандартный ввод. */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <string.h> #include <aio.h> #include <pthread.h> #include <assert.h> /* Указатель на массив указателей на управляющие */ /* блоки запросов операций асинхронного чтения */ static struct aiocb **lio_ptr; /* Общее число строк в файлах */ static long nlines_total = 0; /* Переменная условия, на которой ждут */ /* окончания обработки всех файлов */ static pthread_cond_t open_files_cond = PTHREAD_COND_INITIALIZER; /* Мьютекс, охраняющий доступ */ /* к переменной условия и nlines_total */ static pthread_mutex_t nlines_mutex = PTHREAD_MUTEX_INITIALIZER; /* * * * * * * * * * * * * * */ /* Функция, вызываемая */ /* при завершении операции */ /* асинхронного ввода/вывода */ /* * * * * * * * * * * * * * */ static void end_of_aio_op (union sigval sg_vl) { int no; /* Номер выполненного запроса */ /* в общем списке */ ssize_t nb; /* Число прочитанных байт */ long nlines = 0; /* Число строк в одной */ /* прочитанной порции */ no = sg_vl.sival_int; if ((nb = aio_return (lio_ptr [no])) <= 0) { /* Дошли до конца файла */ /* или чтение завершилось ошибкой */ (void) close (lio_ptr [no]->aio_fildes); free ((void *) lio_ptr [no]->aio_buf); free (lio_ptr [no]); lio_ptr [no] = NULL; (void) pthread_cond_signal (&open_files_cond); } else { /* Обработаем прочитанные данные */ char *p; /* Текущее начало поиска перевода строки */ char *p1; /* Позиция, где нашли перевод строки */ p = (char *) lio_ptr [no]->aio_buf; while ((p1 = (char *) memchr (p, '\n', nb - (p – (char *) lio_ptr [no]->aio_buf))) != NULL) { nlines++; p = p1 + 1; } /* Прибавим локальную сумму к общей */ (void) pthread_mutex_lock (&nlines_mutex); nlines_total += nlines; (void) pthread_mutex_unlock (&nlines_mutex); /* Инициируем новый запрос на чтение */ lio_ptr [no]->aio_offset += nb; (void) aio_read (lio_ptr [no]); } } /* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Функция проверяет, сколько осталось открытых файлов */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ static int n_open_files (int nfiles) { int nof = 0; /* Число открытых файлов */ int i; for (i = 0; i < nfiles; i++) { if (lio_ptr [i] != NULL) { nof++; } } return (nof); } /* * * * * * * * * * * * * * * * * * * * */ /* Обработка аргументов командной строки, */ /* инициация начальных запросов на чтение, */ /* ожидание завершения обработки файлов, */ /* вывод результатов */ /* * * * * * * * * * * * * * * * * * * * */ int main (int argc, char *argv []) { int dup_stdin = 0; /* Признак повторного указания */ /* стандартного ввода */ int i; /* Сведем случай с отсутствием аргументов к общему, */ /* воспользовавшись одним из немногих */ /* стандартизованных файлов */ if (argc == 1) { argv [0] = "-"; } else { argv [0] = "/dev/null"; } /* Зарезервируем память, откроем заданные файлы */ /* и инициируем начальные запросы на чтение */ assert ((lio_ptr = (struct aiocb **) malloc (sizeof (struct aiocb *) * argc)) != NULL); for (i = 0; i < argc; i++) { assert ((lio_ptr [i] = (struct aiocb *) malloc (sizeof (struct aiocb))) != NULL); if (strcmp (argv [i], "-") == 0) { if (dup_stdin == 0) { lio_ptr [i]->aio_fildes = STDIN_FILENO; dup_stdin = 1; } else { lio_ptr [i]->aio_fildes = fcntl (STDIN_FILENO, F_DUPFD, 0); } } else if ((lio_ptr [i]->aio_fildes = open (argv [i], O_RDONLY)) == -1) { perror ("OPEN"); free (lio_ptr [i]); lio_ptr [i] = NULL; continue; } lio_ptr [i]->aio_offset = 0; assert ((lio_ptr [i]->aio_buf = malloc (BUFSIZ)) != NULL); lio_ptr [i]->aio_nbytes = BUFSIZ; lio_ptr [i]->aio_reqprio = 0; lio_ptr [i]->aio_sigevent.sigev_notify = SIGEV_THREAD; lio_ptr [i]->aio_sigevent.sigev_signo = SIGRTMIN; lio_ptr [i]->aio_sigevent.sigev_value.sival_int = i; lio_ptr [i]->aio_sigevent.sigev_notify_function = end_of_aio_op; lio_ptr [i]->aio_sigevent.sigev_notify_attributes = NULL; /* Запрос готов, можно отправлять его на выполнение */ (void) aio_read (lio_ptr [i]); } /* for (i < argc) */ /* Дождемся завершения обработки всех указанных */ /* в командной строке файлов */ while (n_open_files (argc) > 0) { (void) pthread_cond_wait (&open_files_cond, &nlines_mutex); } printf ("%ld\n", nlines_total); return 0; } |
Листинг 7.8. Модифицированный вариант программы, использующей функции асинхронного ввода/вывода. |
Закрыть окно |
#include <fcntl.h> int posix_fadvise ( int fd, off_t offset, size_t len, int advice); #include <fcntl.h> int posix_fallocate (int fd, off_t offset, size_t len); #include <sys/mman.h> int posix_madvise (void *addr, size_t len, int advice); #include <stdlib.h> int posix_memalign (void **memptr, size_t alignment, size_t size); |
Листинг 7.9. Описание функций рекомендательных интерфейсов. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа подсчитывает сумму байт в файле – */ /* аргументе командной строки, */ /* пытаясь оптимизировать чтение данных с помощью */ /* функций */ /* рекомендательных интерфейсов */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #define _XOPEN_SOURCE 600 #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> int main (int argc, char *argv []) { int fd; /* Дескриптор файла-аргумента */ long sum = 0; /* Сумма байт в файле */ char *pbuf; /* Указатель на буфер обмена */ ssize_t nb; /* Число прочитанных байт */ int i; if (argc != 2) { fprintf (stderr, "Использование: %s имя_файла\n", argv [0]); return (1); } /* Откроем заданный файл на чтение */ if ((fd = open (argv [1], O_RDONLY)) == -1) { perror ("OPEN"); return (2); } /* Опишем дисциплину работы с файлом */ if (((errno = posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL)) != 0) || ((errno = posix_fadvise (fd, 0, 0, POSIX_FADV_NOREUSE)) != 0)) { perror ("POSIX_FADVISE"); } /* Зарезервируем память под буфер обмена, */ /* следуя рекомендациям */ /* на выравнивание и размер. */ /* Предполагается, что значение BUFSIZ */ /* кратно всем нужным величинам. */ if ((errno = posix_memalign ((void **) &pbuf, BUFSIZ, BUFSIZ)) != 0) { perror ("POSIX_MEMALIGN"); return (errno); } /* Прочитаем файл и обработаем содержащиеся в нем данные */ while ((nb = read (fd, pbuf, BUFSIZ)) > 0) { for (i = 0; i < nb; i++) { sum += pbuf [i]; } } printf ("%ld\n", sum); free (pbuf); return (close (fd)); } |
Листинг 7.10. Пример программы, использующей функции рекомендательных интерфейсов. |
Закрыть окно |