Асинхронный ввод/вывод, рекомендательные интерфейсы
Функция posix_fallocate() резервирует долговременную память для указанной части файла. После успешного завершения ее работы запись в эту часть файла не может кончиться неудачей из-за нехватки свободного пространства.
Если сумма ( offset + len ) превышает текущий размер файла, он будет соответственно увеличен; в противном случае размер не изменится.
Влияние предыдущих вызовов posix_fadvise() на стратегию выделения долговременной памяти зависит от реализации.
Функция posix_madvise() информирует реализацию об ожидаемом поведении приложения по отношению к части адресного пространства вызывающего процесса, которая начинается с адреса addr и имеет длину len байт. Подобная информация может оказаться полезной, если в указанную область памяти отображен файл. (Реализация имеет право требовать, чтобы область начиналась с границы страницы.)
Ожидаемое поведение специфицирует аргумент advice, который может принимать следующие значения.
POSIX_MADV_NORMAL
Подразумеваемое поведение – отсутствие рекомендаций.
POSIX_MADV_SEQUENTIAL
Предполагается, что приложение будет осуществлять доступ к указанной части адресного пространства последовательно, от меньших адресов к большим.
POSIX_MADV_RANDOM
Специфицирует случайный доступ.
POSIX_MADV_WILLNEED
Предполагается, что данные из указанной части адресного пространства скоро понадобятся.
POSIX_MADV_DONTNEED
Предполагается, что данные из указанной части адресного пространства в ближайшее время не понадобятся.
Функция posix_memalign() служит для резервирования области памяти длины size с начальной границей, выровненной в соответствии со значением аргумента alignment. Результирующий адрес записывается по указателю memptr. Значение alignment должно быть кратным величине sizeof (void *), которая является степенью двойки.
Область памяти, зарезервированную посредством вызова posix_memalign(), в дальнейшем можно освободить с помощью функции free().
При оптимизации обмена данными с файлами, наряду с применением рекомендательных интерфейсов, целесообразно учитывать значения следующих конфигурационных констант, определенных в заголовочном файле <limits.h>, которые можно опросить, обращаясь к функции pathconf().
POSIX_ALLOC_SIZE_MIN
Минимальное число байт долговременной памяти, реально выделяемое для любой части файла.
POSIX_REC_MIN_XFER_SIZE
Минимальное рекомендуемое число передаваемых байт при обмене данными с файлами. Рекомендуется также, чтобы и смещение передаваемой порции данных от начала файла было кратным POSIX_REC_MIN_XFER_SIZE.
POSIX_REC_MAX_XFER_SIZE
Максимальное рекомендуемое число передаваемых байт при обмене данными с файлами.
POSIX_REC_INCR_XFER_SIZE
Рекомендуемое приращение числа передаваемых байт при обмене данными с файлами (в диапазоне от POSIX_REC_MIN_XFER_SIZE до POSIX_REC_MAX_XFER_SIZE ).
POSIX_REC_XFER_ALIGN
Рекомендуемое значение для выравнивания границы буфера обмена данными с файлами.
Применение функций рекомендательных интерфейсов проиллюстрируем программой, подсчитывающей сумму байт в файле (см. листинг 7.10).
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа подсчитывает сумму байт в файле – */ /* аргументе командной строки, */ /* пытаясь оптимизировать чтение данных с помощью */ /* функций */ /* рекомендательных интерфейсов */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #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. Пример программы, использующей функции рекомендательных интерфейсов.
В этой программе задействовано несколько оптимизирующих факторов. Во-первых, посредством вызовов posix_fadvise() системе сообщается, что ко всему файлу (от начала до конца) будет осуществляться только однократный последовательный доступ. Во-вторых, память под буфер обмена резервируется с соблюдением рекомендаций на выравнивание и размер. Читателю предлагается самостоятельно определить реальный вклад каждого оптимизирующего фактора.