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).
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?