Как узнать, когда требуется сброс буфера?

Учитывая две функции, которые очищают буферы:

  1. fflush()
  2. sync()

Как я могу узнать, когда требуется вызов любого из них?

Я знаю, что добавление '\n' к printf() очистит выходной буфер, но если строка не содержит такого символа, когда я могу пропустить этот вызов, а когда нет (многопоточные системы?)?

То же самое касается sync. У меня есть функция, которая сохраняет файлы в файловую систему (сохранение происходит через серию системных вызовов), и похоже, что без вызова sync файлы не сохраняются в конкретном случае

К сожалению, в настоящее время у меня нет всех подробностей по этому делу [Что я знаю, так это то, что файлы сохраняются, и сразу после этого происходит отключение питания (точно не знаю, как скоро) и файлов нет после перезагрузки]. Во всех тестах, которые я запускал, файлы сохранялись правильно.

Итак, как я могу выяснить, когда система будет очищать буферы файловых данных/метаданных, а когда нет, и мне нужно явно вызывать sync()?

Цитирование man (в котором не указано, когда требуется явный вызов):

sync, syncfs - commit buffer cache to disk
sync() causes all buffered modifications to file metadata and data to be written to the underlying file systems.

fflush - flush a stream
For  output  streams,  fflush() forces a write of all user-space buffered data for the given output or update stream via the stream's underlying write function.  For input streams, fflush() discards any buffered data that has been fetched from the underlying file, but has not been consumed by the application.  The open status  of the stream is unaffected.

Дополнительный вопрос:

В первом комментарии к этому ответу показан способ отключения буферизации stdout с помощью setbuf(stdout, NULL);. Есть ли что-то подобное для sync (какой буфер для этого используется?)?


person CIsForCookies    schedule 02.10.2018    source источник
comment
добавление '\n' к printf() приведет к очистке выходного буфера --> В общем - возможно: Каковы правила автоматической очистки буфер stdout в C?. Тем не менее, это может быть указано для Linux.   -  person chux - Reinstate Monica    schedule 02.10.2018
comment
Я думаю, что на этот вопрос нет общего ответа. Очистка и синхронизация — это просто функции, предоставляемые C lib. ВЫ будете знать, когда его использовать, когда ВЫ разработаете алгоритм своей программы.   -  person Joël Hecht    schedule 02.10.2018
comment
CIsForCookies У вас есть мой UV, но когда он необходим, 1) Прямо перед вводом данных пользователем 2) Прямо перед печатью сообщения об ошибке, 3) Когда захотите.   -  person chux - Reinstate Monica    schedule 02.10.2018


Ответы (1)


sync()

Вам редко нужен вызов sync(). Когда вы это сделаете, у вас есть что-то, что очень важно, должно быть записано на диск как можно скорее. Однако sync() вернется, запланировав запись буферов в память ядра, а не после того, как они были записаны, так что вы не будете знать, что они действительно были записаны, так что это не совсем надежно. Если вам нужно больше контроля над написанием файла, обратите внимание на флаги O_SYNC, O_DSYNC, O_RSYNC для open(). Возможно, вам придется использовать fcntl() и fileno(), чтобы установить эти флаги, если вы используете файловые потоки, а не файловые дескрипторы.

Два предостережения:

  1. sync() не будет записывать буферы вашего процесса (или любого другого процесса) в пул буферов ядра; это совершенно не связано с fflush().
  2. sync() влияет на все данные, записываемые всеми процессами в системе — вы можете стать непопулярным, если ваше приложение использует его очень часто; это подрывает хорошую работу ядра по кэшированию данных.

fflush()

Функция fflush() гарантирует, что данные были записаны в буферные пулы ядра. из буфера вашего приложения (либо для одного файла, либо для всех выходных файлов, если вы используете fflush(0) или fflush(NULL)). Это не влияет напрямую на другие процессы. Опять же, вы используете это, когда вам нужно быть уверенным, что ожидающий вывод был отправлен ядру для дальнейшей передачи. Одно место, где вы можете использовать его, — это перед операцией ввода, где вы хотите, чтобы подсказка отображалась, даже если в конце нет новой строки. В противном случае вы не будете использовать его часто, но вы можете использовать его всякий раз, когда хотите быть уверенным, что данные отправлены в ядро ​​для записи. Если вы отлаживаете и ваша программа дает сбой, небольшое количество операторов fflush() может гарантировать, что ожидающий вывод будет записан до сбоя. Это может помочь более точно определить, в чем проблема (но то же самое можно сделать и с помощью отладчика).

Обратите внимание, что установка небуферизованного вывода (setbuf(stdout, NULL) или setvbuf(stdout, NULL, _IONBF, 0)) означает, что весь вывод происходит "немедленно". Это не обязательно хорошо для производительности. Вы используете его иногда, но довольно редко.

person Jonathan Leffler    schedule 02.10.2018