wake-up-neo.com

Unterschied zwischen fflush und fsync

Ich dachte, dass fsync () intern fflush () tut, also ist die Verwendung von fsync () für einen Stream in Ordnung. Ich erhalte jedoch ein unerwartetes Ergebnis, wenn es unter Netzwerk-E/A ausgeführt wird.

Mein Code-Snippet:

FILE* fp = fopen(file,"wb");
/* multiple fputs() call 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);

Es scheint jedoch, dass _commit () die Daten nicht leert (ich habe es unter Windows versucht, und die Daten wurden unter Linux exportiert).

Wenn ich den Code geändert habe als:

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

Diesmal werden die Daten gelöscht.

Ich frage mich, ob _commit () dasselbe tut wie fflush (). Irgendwelche eingaben?

44
Adil

fflush() arbeitet mit FILE*, es werden nur die internen Puffer im FILE* Ihrer Anwendung an das Betriebssystem ausgegeben.

fsync arbeitet auf einer niedrigeren Ebene und weist das Betriebssystem an, die Puffer auf die physischen Medien zu leeren.

Betriebssysteme speichern Daten, die Sie in eine Datei schreiben, stark zwischen. Wenn das Betriebssystem jeden Schreibvorgang erzwingt, um das Laufwerk zu treffen, wären die Dinge sehr langsam. fsync (ua) ermöglicht Ihnen zu steuern, wann die Daten auf das Laufwerk gelangen.

Außerdem arbeitet fsync/commit mit einem Dateideskriptor. Es hat keine Kenntnis von einem FILE* und kann seine Puffer nicht leeren. FILE* lebt in Ihrer Anwendung, Dateideskriptoren befinden sich normalerweise im Betriebssystemkern.

70
nos

Die Standard-C-Funktion fflush() und der POSIX-Systemaufruf fsync() sind konzeptionell ähnlich. fflush() arbeitet für C-Dateistreams (FILE-Objekte) und ist daher portabel .fsync() für POSIX-Dateideskriptoren . Beide bewirken, dass gepufferte Daten an ein Ziel gesendet werden.

Auf einem POSIX-System verfügt jeder C-Dateistream über einen zugehörigen Dateideskriptor , und alle Vorgänge in einem C-File-Stream werden implementiert, indem erforderlichenfalls an POSIX-Systemaufrufe delegiert wird, die den Dateideskriptor bearbeiten.

Man könnte meinen, ein Aufruf von fflush auf einem POSIX-System würde eine write der Daten im Puffer des Dateistreams verursachen, gefolgt von einem Aufruf von fsync() für den Dateideskriptor dieses Dateistreams. Auf einem POSIX-System ist es daher nicht erforderlich, einen Aufruf von fflush mit einem Aufruf von fsync(fileno(fp)) zu verfolgen. Aber ist das der Fall: Gibt es einen Aufruf von fsync an fflush?

Nein, der Aufruf von fflush auf einem POSIX-System bedeutet nicht, dass fsync aufgerufen wird.

Der C-Standard für fflush sagt (Hervorhebung hinzugefügt)

veranlasst, dass ungeschriebene Daten für den [Stream] an die Host-Umgebung geschrieben werden an die Datei übermittelt werden

Die Angabe, dass die Daten zu sein geschrieben sind, anstatt dass ist geschrieben ist, impliziert, dass weitere Pufferung durch die Host-Umgebung zulässig ist. Diese Pufferung durch die "Host-Umgebung" könnte für eine POSIX-Umgebung die interne Pufferung umfassen, die von fsync geleert wird. Eine genaue Lektüre des C-Standards legt also nahe, dass die POSIX-Implementierung nicht für den Aufruf von fsync erforderlich ist.

Die POSIX-Standardbeschreibung von fflush erklärt nicht als Erweiterung der C-Semantik , dass fsync aufgerufen wird.

5
Raedwald

Ich könnte das der Einfachheit halber sagen:

verwenden Sie fsync() ohne Streaming-Dateien (Ganzzahl-Dateideskriptoren).

verwenden Sie fflush() mit Dateistreams.

Auch hier ist die Hilfe des Menschen:

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
2
pulse

fflush() und fsync() können verwendet werden, um sicherzustellen, dass Daten auf das Speichermedium geschrieben werden (dies ist jedoch nicht immer möglich):

  1. verwenden Sie zuerst fflush(fp) für den Ausgabestream (fp ist ein FILE *, der aus fopen oder einem der Standard-Streams stdout oder stderr), um den Inhalt des Puffers, der dem Stream zugeordnet ist, in das Betriebssystem zu schreiben.
  2. verwenden Sie dann fsync(fileno(fp)), um das Betriebssystem anzuweisen, seine eigenen Puffer auf das Speichermedium zu schreiben.

Beachten Sie jedoch, dass es sich bei fileno() und fsync() um POSIX-Funktionen handelt, die möglicherweise nicht auf allen Systemen verfügbar sind, insbesondere bei Microsoft-Legacy-Systemen, bei denen Alternativen möglicherweise als _fileno(), _fsync() oder _commit()...

0
chqrlie

Ich denke, das folgende Dokument von Python ( https://docs.python.org/2/library/os.html ) klärt es sehr gut.

os.fsync (fd) Erzwingt das Schreiben der Datei mit dem Fidesescriptor fd auf die Festplatte. Auf Unix ruft die native fsync () - Funktion auf; unter Windows die MS _commit () - Funktion.

Wenn Sie mit einem Python-Dateiobjekt f beginnen, führen Sie zuerst f.flush (), .__ aus. und führen Sie dann os.fsync (f.fileno ()) aus, um sicherzustellen, dass alle internen Puffer f zugeordnet werden, werden auf die Festplatte geschrieben.

Verfügbarkeit: Unix und Windows ab 2.2.3.

0
poordeveloper

Verwenden Sie die Funktionen sync () oder fsync (), um die Übernahme der letzten Änderungen auf der Festplatte zu erzwingen. 

fsync ()synchronisiert alle Daten und Metadaten der angegebenen Datei mit dem permanenten Speichergerät. Es sollte kurz vor dem Schließen der entsprechenden Datei aufgerufen werden. 

sync ()schreibt alle geänderten Dateien auf die Festplatte.

0
user3428045