Подтвердить что ты не робот

Разница между 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(). Любые входы?

4b9b3361

Ответ 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() могут использоваться для проверки и записи данных на носитель (но это не всегда возможно):

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

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