Чтобы избежать этой проблемы, возникающей при смешивании системных вызовов и функций stdio для ввода-вывода, может потребоваться грамотное использование функции fflush(). Буферизацию также можно отключить с помощью функций setvbuf() или setbuf(), но это может повлиять на производительность ввода-вывода в приложении, поскольку в дальнейшем каждая операция вывода приведет к выполнению системного вызова write().

В SUSv3 приводится (длинный) список требований к приложениям, в которых допустимо смешивать системные вызовы и функции stdio для ввода-вывода. Подробности можно найти в разделе Interaction of File Descriptors and Standard I/O Streams в главе General Information тома System Interfaces (XSH).

13.8. Резюме

Буферизация входных и выходных данных выполняется ядром, а также библиотекой stdio. В некоторых случаях может понадобиться предотвратить буферизацию, но при этом нужно учитывать влияние, оказываемое на производительность приложения. Для управления буферизацией, выполняемой в ядре и осуществляемой библиотечными функциями, и для однократных сбросов буферов можно использовать разнообразные системные вызовы и библиотечные функции.

Для уведомления ядра о предпочитаемой схеме обращения к данным из указанного файла процесс может воспользоваться функцией posix_fadvise(). Ядро может применить эту информацию для оптимизации применения буферной кэш-памяти, повысив таким образом производительность ввода-вывода.

Характерный для Linux флаг O_DIRECT, используемый при системном вызове open(), позволяет специализированным приложениям обходить буферную кэш-память.

Функции fileno() и fdopen() помогают решить задачу смешивания системных вызовов и стандартных библиотечных функций языка C, чтобы выполнять ввод-вывод в отношении одного и того же файла. Для заданного потока функция fileno() возвращает соответствующий дескриптор файла, а функция fdopen() выполняет обратную операцию, создавая новый поток, который использует указанный открытый дескриптор файла.

Дополнительная информация

Описание реализации и преимуществ использования буферной кэш-памяти в System V приводится в издании [Bach, 1986]. В книгах [Goodheart & Cox, 1994] и [Vahalia, 1996] также дается описание целесообразности применения и реализации буферной кэш-памяти в System V. Дополнительную информацию, характерную для Linux, можно найти в изданиях [Bovet & Cesati, 2005] и [Love, 2010].

13.9. Упражнения

13.1. Используя встроенную команду оболочки time, попробуйте замерить время работы программы из листинга 4.1 (copy.c) в своей системе:

1) проведите эксперименты с использованием различных размеров файлов и буферов памяти. Размер буфера памяти можно задать при компилировании программы с помощью ключа — DBUF_SIZE=nbytes;

2) добавьте флаг O_SYNC в системный вызов open(). Определите, насколько это повлияет на скорость при различных размерах буферной памяти;

3) попробуйте выполнить тесты по замеру времени в нескольких файловых системах (например, ext3, XFS, Btrfs и JFS). Будут ли результаты похожи друг на друга? Будет ли совпадать динамика при переходе от небольших к большим размерам буферов памяти?

13.2. Замерьте время работы программы filebuff/write_bytes.c (предоставляемой в исходном коде, распространяемом для этой книги) для различных размеров буферов памяти и файловых систем.

13.3. Каким будет эффект использования следующих инструкций?

fflush(fp);

fsync(fileno(fp));

13.4. Объясните, почему вывод при выполнении следующего кода изменяется в зависимости от того, куда перенаправляется стандартный вывод — на терминал или в дисковый файл.

printf("If I had more time, \n");

write(STDOUT_FILENO, "I would have written you a shorter letter.\n", 43);

13.5. Команда tail [— n num] file выводит последние num строк (по умолчанию десять) указанного файла. Реализуйте эту команду, используя системные вызовы ввода-вывода (lseek(), read(), write() и т. д.). Чтобы реализация работала эффективно, не забудьте про рассмотренные в этой главе вопросы буферизации.

<p>14. Файловые системы</p>

В главах 4, 5 и 13 мы рассмотрели файловый ввод-вывод, уделив особое внимание обычным (то есть дисковым) файлам. В этой и последующих главах мы более подробно разберем некоторые темы, связанные с файлами.

• В текущей главе речь идет о файловых системах.

• В главе 15 описаны различные атрибуты файла, включая метки времени, принадлежность и права доступа.

• В главах 16 и 17 обсуждаются две новые особенности системы Linux 2.6: расширенные атрибуты и списки контроля доступа (ACL). Расширенные атрибуты — это способ привязки произвольных метаданных к файлу. Списки контроля доступа — это расширенный вариант традиционной UNIX-модели прав доступа к файлу.

• В главе 18 рассмотрены каталоги и ссылки.

Перейти на страницу:

Похожие книги