Во многих реализациях библиотек языка C, включая glibc, если stdin и stdout ссылаются на терминал, при каждом считывании ввода из stdin происходит скрытое выполнение fflush(stdout). Это выражается в сбросе всех приглашений к вводу, которые записаны в stdout и не включают в себя завершающий символ новой строки (например, printf("Date: ")). Но такое поведение не указано в SUSv3 или C99 и реализовано не во всех библиотеках языка C. Для обеспечения отображения таких приглашений к вводу портируемые программы должны использовать явно указанные вызовы fflush(stdout).
В стандарте C99 изложены два требования для той ситуации, когда поток открыт как для ввода, так и для вывода. Во-первых, за операциями вывода не могут непосредственно следовать операции ввода без выполняемого между ними вызова fflush() или одной из функций позиционирования файлового указателя (fseek(), fsetpos() или rewind()). Во-вторых, за операцией ввода не может непосредственно следовать операция вывода без выполняемого между ними вызова одной из функций позиционирования файлового указателя, если только операция ввода не столкнулась с окончанием файла.
Сброс буферной памяти ядра для файлов вывода можно сделать принудительным. Иногда это необходимо, если приложение, прежде чем продолжить работу (например, процесс, журналирущий изменения базы данных), должно гарантировать фактическую запись вывода на диск (или как минимум в аппаратный кэш диска).
Перед тем как рассматривать системные вызовы, используемые для управления буферизацией в ядре, будет нелишним рассмотреть несколько относящихся к этому вопросу определений из SUSv3.
В SUSv3 понятие
В SUSv3 определяются два различных типа завершений синхронизированного ввода-вывода. Различие между типами касается
Первым типом завершения синхронизированного ввода-вывода в SUSv3 является
• Для операции чтения это означает, что запрошенные данные файла были перенесены (с диска) в процесс. Если есть отложенные операции записи, которые могут повлиять на запрошенные данные, данные будут перенесены на диск до выполнения чтения.
• Для операции записи это означает, что данные, указанные в запросе на запись, были перенесены (на диск), как и все метаданные файла, требуемые для извлечения этих данных. Ключевой момент, на который нужно обратить внимание: чтобы обеспечить извлечение данных из измененного файла, необязательно переносить все медатанные файла. В качестве примера атрибута метаданных измененного файла, который нуждается в переносе, можно привести его размер (если операция записи приводит к увеличению размера файла). В противоположность этому метки времени изменяемого файла не будут нуждаться в переносе на диск до того, как произойдет последующее извлечение данных.
Вторым типом завершения синхронизированного ввода-вывода, определенного в SUSv3, является
Системный вызов fsync() приводит к сбросу всех буферизованных данных и всех метаданных, которые связаны с открытым файлом, имеющим дескриптор fd. Вызов fsync() приводит файл в состояние целостности (файла) после завершения синхронного ввода-вывода.