Атомность `write (2)` к локальной файловой системе
Очевидно, POSIX утверждает, что
Дескриптор файла или поток называется «дескриптором» описания открытого файла, к которому он относится; описание открытого файла может иметь несколько дескрипторов. […] Все действия приложения, влияющие на смещение файла на первом дескрипторе, должны быть приостановлены до тех пор, пока он снова не станет активным дескриптором файла. […] Дескрипторы не должны быть в одном и том же процессе для применения этих правил. - POSIX.1-2008
а такж
Если два потока вызывают каждый [функцию write ()], каждый вызов должен видеть либо все указанные эффекты другого вызова, либо ни одного из них. - POSIX.1-2008
Я понимаю, что когда первый процесс выдаетwrite(handle, data1, size1)
и второй процесс выдаетwrite(handle, data2, size2)
, запись может происходить в любом порядке, кромеdata1
а такжеdata2
долже будь и нетронутым, и непрерывным.
Но выполнение следующего кода дает мне неожиданные результаты.
#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);
}
Я попытался запустить это на Linux и Mac OS X 10.7.4 и использоватьgrep -a '^[^-]\|^..*-' /tmp/atomic-write.log
показывает, что некоторые записи не являются непрерывными или перекрываются (Linux) или просто повреждены (Mac OS X).
Добавление флагаO_APPEND
вopen(2)
call решает эту проблему. Приятно, но я не понимаю почему. POSIX говорит
O_APPEND Если установлено, смещение файла должно быть установлено до конца файла перед каждой записью.
но это не проблема здесь. Моя программа-пример никогда не делаетlseek(2)
но с одинаковым описанием файла и таким же смещением файла.
Я уже читал похожие вопросы о Stackoverflow, но они все еще не полностью отвечают на мой вопрос.
Атомная запись в файл из двух процессов конкретно не рассматривает случай, когда процессы совместно используют один и тот жеописание файл (в отличие от того же файла).
Как программно определить, является ли системный вызов «write» атомарным для определенного файла? Говорит, чт
Thewrite
@ call, как определено в POSIX, вообще нет гарантии атомарности.
Но цитируется выше у него есть. И более того,O_APPEND
, кажется, вызывает эту гарантию атомарности, хотя мне кажется, что эта гарантия должна присутствовать даже безO_APPEND
.
Можете ли вы объяснить это поведение?