Разница между fflush и fsync
Я думал, что 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()
не _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()
. Любые входы?
Ответы
Ответ 1
fflush()
работает на FILE*
, он просто очищает внутренние буферы в FILE*
вашего приложения от ОС.
fsync
работает на более низком уровне, он сообщает ОС, чтобы сбросить свои буферы на физический носитель.
ОС сильно кэшируют данные, которые вы пишете в файл. Если ОС принудительно применяет каждую запись, чтобы попасть на диск, все будет очень медленно. fsync
(между прочим) позволяет вам контролировать, когда данные должны попадать на диск.
Кроме того, fsync/commit работает с файловым дескриптором. Он не знает о FILE*
и не может очищать свои буферы. FILE*
живет в вашем приложении, файловые дескрипторы живут в ядре ОС, как правило.
Ответ 2
Стандартная функция 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
.
Стандартное описание fflush
POSIX не объявляет, как расширение семантики C, что fsync
вызывается.
Ответ 3
Я мог бы сказать, что для простоты:
использовать fsync()
с не потоковыми файлами (дескрипторы целочисленных файлов)
используйте fflush()
с файловыми потоками.
Также здесь помощь от человека:
int fflush(FILE *stream); // flush a stream, FILE* type
int fsync(int fd); // synchronize a file in-core state with storage device
// int type
Ответ 4
Чтобы принудительно использовать последние изменения на диске, используйте функции sync() или fsync().
fsync() синхронизирует все данные файла и метаданные с постоянным запоминающим устройством. Он должен быть вызван непосредственно перед закрытием соответствующего файла.
sync() передаст все измененные файлы на диск.
Ответ 5
Я думаю, что ниже документ из python (https://docs.python.org/2/library/os.html) очень хорошо его разъясняет.
os.fsync(fd) Принудительная запись файла с filedescriptor fd на диск. На Unix, это вызывает встроенную функцию fsync(); на Windows, MS _commit().
Если вы начинаете с файлового объекта Python f, сначала выполните f.flush(), а затем выполните os.fsync(f.fileno()), чтобы убедиться, что все внутренние буферы связанные с f записываются на диск.
Доступность: Unix и Windows, начиная с 2.2.3.
Ответ 6
fflush()
и fsync()
могут использоваться для проверки и записи данных на носитель (но это не всегда возможно):
- сначала используйте
fflush(fp)
в выходном потоке (fp
- это FILE *
полученный из fopen
или одного из стандартных потоков stdout
или stderr
), чтобы записать содержимое буфера, связанного с потоком, в ОС. - затем используйте
fsync(fileno(fp))
чтобы указать ОС записывать свои собственные буферы на носитель.
Однако обратите внимание, что fileno()
и fsync()
являются функциями POSIX, которые могут быть недоступны во всех системах, особенно в устаревших системах Microsoft, где альтернативы могут называться _fileno()
, _fsync()
или _commit()
...