По-видимому, POSIX утверждает, что
Либо файловый дескриптор, либо поток называется "дескриптором" на открыть описание файла, на который он ссылается; описание открытого файла может иметь несколько ручек. […] Вся активность приложения влияющие на смещение файла на первом дескрипторе должны быть приостановлены пока он снова не станет активным дескриптором файла. […] Ручки нужны не находиться в одном и том же процессе для применения этих правил. -- POSIX.1-2008
и
Если каждый из двух потоков вызывает [функцию write()], каждый вызов должен либо увидеть все указанные эффекты другого вызова, либо ничего их. -- POSIX.1-2008
Насколько я понимаю, когда первый процесс выдает
write(handle, data1, size1)
и второй процесс выдает
write(handle, data2, size2)
записи могут выполняться в любом порядке, кроме
данные1
и данные2
должныбыть как чистыми, так и непрерывными.
Но запуск следующего кода дает неожиданные результаты.
#include
#include
#include
#include
#include
#include
#include
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)
исправляет это.
проблема. Красиво, но я не понимаю, почему. POSIX говорит
O_APPEND Если установлено, смещение файла должно быть установлено в конец файла перед каждой записью.
но здесь проблема не в этом. Моя примерная программа никогда не
lseek(2)
, но имеют одно и то же описание файла и, следовательно, один и тот же файл
компенсировать.
Я уже читал подобные вопросы на Stackoverflow, но они не полностью ответьте на мой вопрос.
Атомарная запись в файл из двух процессовспециально не устранить случай, когда процессы используют одно и то же описание файла (в отличие от того же файла).
Как программно определить, является ли системный вызов «запись» атомарным для конкретного файла? говорится, что
вызов
write
, определенный в POSIX, вообще не гарантирует атомарности.
Но, как процитировано выше, у него есть некоторые.И более того,
O_APPEND
, кажется, запускает эту гарантию атомарности, хотя кажется
мне, что эта гарантия должна присутствовать даже без O_APPEND
.
Можете ли вы объяснить это поведение?