Разница между fflush и fsync - PullRequest
       14

Разница между fflush и fsync

47 голосов
/ 26 февраля 2010

Я думал, fsync() делает fflush() внутренне, поэтому использование fsync() в потоке - это нормально. Но я получаю неожиданный результат при выполнении при сетевом вводе / выводе.

Мой фрагмент кода:

FILE* fp = fopen(file, "wb");
/* multiple fputs() calls like: */
fputs(buf, fp);
...
...
fputs(buf.c_str(), fp);
/* get fd of the FILE pointer */
fd = fileno(fp);
#ifndef WIN32
ret = fsync(fd);
#else
ret = _commit(fd);
fclose(fp);

Но, похоже, _commit() не сбрасывает данные (я пробовал в Windows, а данные были записаны в экспортированной файловой системе Linux).

Когда я изменил код на:

FILE* fp = fopen(file, "wb");
/* multiple fputs() calls like: */
fputs(buf, fp);   
...   
...
fputs(buf.c_str(), fp);
/* fflush the data */
fflush(fp);
fclose(fp);

сбрасывает данные.

Мне интересно, если _commit() делает то же самое, что и fflush(). Любые входы?

Ответы [ 6 ]

74 голосов
/ 26 февраля 2010

fflush() работает на FILE*, просто сбрасывает внутренние буферы в FILE* вашего приложения в ОС.

fsync работает на более низком уровне, он говорит ОС сбрасывать свои буферы на физический носитель.

ОС сильно кэшируют данные, которые вы записываете в файл. Если бы ОС заставляла каждую запись попадать на диск, все было бы очень медленным. fsync (среди прочего) позволяет вам контролировать, когда данные должны попасть на диск.

Кроме того, fsync / commit работает с дескриптором файла. Он не знает FILE* и не может очистить свои буферы. FILE* живет в вашем приложении, дескрипторы файлов, как правило, живут в ядре ОС.

5 голосов
/ 12 января 2017

Стандартная функция C fflush() и системный вызов POSIX fsync() концептуально несколько похожи. fflush() работает с потоками файлов C (FILE объекты) и поэтому является переносимым. fsync() работает с дескрипторами файлов POSIX. И то, и другое приводит к отправке буферизованных данных в пункт назначения.

В системе POSIX каждый поток файлов C имеет соответствующий дескриптор файла , и все операции с потоком файлов C будут реализованы путем делегирования, при необходимости, системным вызовам POSIX, которые работают на дескриптор файла.

Можно подумать, что вызов fflush в системе POSIX вызовет write любых данных в буфере файлового потока, после чего вызовет fsync() для файлового дескриптора этого файлового потока. , Таким образом, в системе POSIX не было бы необходимости следовать вызову fflush и вызову fsync(fileno(fp)). Но так ли это: звонит ли fsync с fflush?

Нет, вызов fflush в системе POSIX не означает, что будет вызываться fsync.

Стандарт C для fflush говорит (выделено)

вызывает доставку любых неписанных данных для потока [] в среду хоста. для записи в файл

.

Утверждение, что данные должны быть записаны , а не записано означает, что дальнейшая буферизация средой хоста разрешена. Эта буферизация "средой хоста" может включать в себя для среды POSIX внутреннюю буферизацию, которая сбрасывается fsync. Таким образом, внимательное прочтение стандарта C предполагает, что стандарт не требует реализации POSIX для вызова fsync.

Стандартное описание POSIX fflush не объявляет, как расширение семантики C , что fsync вызывается.

2 голосов
/ 04 февраля 2015

Я могу сказать, что для простоты:

использовать fsync() с не потоковыми файлами (целочисленные файловые дескрипторы)

использовать fflush() с файловыми потоками.

Также вот помощь от человека:

int fflush(FILE *stream); // flush a stream, FILE* type

int fsync(int fd); // synchronize a file's in-core state with storage device
                    // int type
0 голосов
/ 27 июня 2019

fflush() и fsync() могут использоваться для проверки и записи данных на носитель (но это не всегда возможно):

  1. сначала используйте fflush(fp) в выходном потоке (fp представляет собой FILE *, полученный из fopen или одного из стандартных потоков stdout или stderr), чтобы записать содержимое буфера, связанного с поток в ОС.
  2. затем используйте fsync(fileno(fp)), чтобы указать ОС записывать свои собственные буферы на носитель.

Обратите внимание, однако, что fileno() и fsync() - это функции POSIX, которые могут быть недоступны во всех системах, особенно в устаревших системах Microsoft, где альтернативы могут называться _fileno(), _fsync() или _commit() ... * 1023. *

0 голосов
/ 23 ноября 2017

Я думаю, что ниже документ от Python (https://docs.python.org/2/library/os.html) очень хорошо разъясняет.

os.fsync (fd) Принудительная запись файла с файловым дескриптором fd на диск. На Unix, это вызывает встроенную функцию fsync (); на винде мс Функция _commit ().

Если вы начинаете с файлового объекта Python f, сначала выполните f.flush (), а затем выполните os.fsync (f.fileno ()), чтобы убедиться, что все внутренние буферы связанные с f записываются на диск.

Доступность: Unix и Windows, начиная с 2.2.3.

0 голосов
/ 05 марта 2015

Чтобы принудительно зафиксировать последние изменения на диске, используйте функции sync () или fsync ().

fsync () синхронизирует все данные и метаданные данного файла с постоянным устройством хранения. Он должен быть вызван непосредственно перед тем, как соответствующий файл был закрыт.

sync () передаст все измененные файлы на диск.

...