Atomicity of `write (2)` in ein lokales Dateisystem

Anscheinend gibt POSIX das an

Entweder ein Dateideskriptor oder ein Stream wird als "Handle" für die geöffnete Dateibeschreibung bezeichnet, auf die er verweist. Eine offene Dateibeschreibung kann mehrere Punkte haben. […] Alle Aktivitäten der Anwendung, die sich auf den Dateiversatz des ersten Handles auswirken, werden ausgesetzt, bis es wieder zum aktiven Dateiverteiler wird. […] Die Punkte müssen sich nicht im selben Prozess befinden, damit diese Regeln gelten. -POSIX.1-2008

und

Wenn zwei Threads für jeden Aufruf [die write () - Funktion] vorhanden sind, werden für jeden Aufruf entweder alle angegebenen Auswirkungen des anderen Aufrufs oder keine davon angezeigt. -POSIX.1-2008

Ich verstehe dies so, dass wenn der erste Prozess awrite(handle, data1, size1) und der zweite Prozess Fragenwrite(handle, data2, size2), die Schreibvorgänge können in beliebiger Reihenfolge außer der erfolgendata1 unddata2 Muss sei sowohl makellos als auch zusammenhängend.

Der folgende Code führt jedoch zu unerwarteten Ergebnissen.

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
die(char *s)
{
  perror(s);
  abort();
}

main()
{
  unsigned char buffer[3];
  char *filename = "/tmp/atomic-write.log";
  int fd, i, j;
  pid_t pid;
  unlink(filename);
  /* XXX Adding O_APPEND to the flags cures it. Why? */
  fd = open(filename, O_CREAT|O_WRONLY/*|O_APPEND*/, 0644);
  if (fd < 0)
    die("open failed");
  for (i = 0; i < 10; i++) {
    pid = fork();
    if (pid < 0)
      die("fork failed");
    else if (! pid) {
      j = 3 + i % (sizeof(buffer) - 2);
      memset(buffer, i % 26 + 'A', sizeof(buffer));
      buffer[0] = '-';
      buffer[j - 1] = '\n';
      for (i = 0; i < 1000; i++)
        if (write(fd, buffer, j) != j)
          die("write failed");
      exit(0);
    }
  }
  while (wait(NULL) != -1)
    /* NOOP */;
  exit(0);
}

Ich habe versucht, dies unter Linux und Mac OS X 10.7.4 auszuführen und zu verwendengrep -a '^[^-]\|^..*-' /tmp/atomic-write.log zeigt, dass einige Schreibvorgänge nicht zusammenhängend oder überlappend sind (Linux) oder einfach beschädigt sind (Mac OS X).

Hinzufügen der FlaggeO_APPEND in demopen(2) Anruf behebt dieses Problem. Schön, aber ich verstehe nicht warum. POSIX sagt

O_APPEND Wenn gesetzt, wird der Dateiversatz vor jedem Schreibvorgang auf das Dateiende gesetzt.

aber das ist hier nicht das problem. Mein Beispielprogramm macht das nielseek(2) teilen Sie aber die gleiche Dateibeschreibung und damit den gleichen Dateiversatz.

Ich habe ähnliche Fragen zu Stackoverflow bereits gelesen, aber sie beantworten meine Frage immer noch nicht vollständig.

Atomarer Schreibvorgang für zwei Prozesse befasst sich nicht speziell mit dem Fall, in dem die Prozesse gleich sindDateibeschreibung (im Gegensatz zu der gleichen Datei).

Wie kann man programmgesteuert feststellen, ob der Systemaufruf "write" für eine bestimmte Datei atomar ist? sagt, dass

Daswrite Der in POSIX definierte Aufruf hat überhaupt keine Atomizitätsgarantie.

AberOben zitiert es hat einige. Und außerdem,O_APPEND scheint diese Atomgarantie auszulösen, obwohl mir scheint, dass diese Garantie auch ohne vorhanden sein sollteO_APPEND.

Können Sie dieses Verhalten näher erläutern?

Antworten auf die Frage(4)

Ihre Antwort auf die Frage