我有一个案例,其中有两个进程作用于同一个文件 - 一个作为编写者,一个作为读者。该文件是一行文本文件,编写器在循环中重写该行。读者读取该行。伪代码如下所示:
作家流程
char buf[][18] = {
"xxxxxxxxxxxxxxxx",
"yyyyyyyyyyyyyyyy"
};
i = 0;
while (1) {
pwrite(fd, buf[i], 18, 0);
i = (i + 1) % 2;
}
读者流程
while(1) {
pread(fd, readbuf, 18, 0);
//check if readbuf is either buf[0] or buf[1]
}
运行这两个流程一段时间后,我可以看到readbuf
是xxxxxxxxxxxxxxxxyy
或yyyyyyyyyyyyyyyyxx
。
我的理解是写入对于大小为512字节的大小是原子的。但是从我的实验来看,原子性看起来只有16个字节。
手册页没有说明普通文件的原子性,它只提到512字节的管道原子性。
我用tmpfs和ext4尝试了这个,结果是一样的。使用O_SYNC
,ext4写入成为原子并且我理解它,因为写入在它到达磁盘之前不会返回,但是O_SYNC
对tmpfs(/dev/shm
)没有帮助。
答案 0 :(得分:4)
POSIX不对read
和write
的原子操作提供任何最低保证,除了管道上的写入(写入最多PIPE_BUF
(≥512)字节是保证是原子的,但读取没有原子性保证)。 read
和write
的操作以字节值描述;除了管道之外,与围绕单字节write
操作的循环相比,write
操作不提供额外的保证。
我不知道Linux会给出任何额外的保证,无论是16还是512.在实践中,我希望它依赖于内核版本,文件系统,以及可能还有其他因素,如底层块设备,CPU数量,CPU架构等。
可选synchronized I/O data integrity completion中为O_SYNC
和O_RSYNC
提供的O_DSYNC
,read
和write
保证SIO POSIX的功能)不是你需要的。它们保证在read
或write
系统调用之前将写入提交到持久存储,但不对write
操作时启动的read
提出任何声明。正在进行中。
在您的方案中,读取和写入文件看起来不像正确的工具集。
mmap
。这并不能神奇地解决原子性问题,但可能会提高正确同步机制的性能。要执行同步,有两种基本方法:
mmap
+ msync
)或不同的渠道(例如管道)。msync
)。然后,生产者将一个众所周知的值写入一个机器字(sig_atomic_t
通常会起作用,即使其原子性仅在信号上正式保证 - 或者实际上是uintptr_t
)。消费者读取一个机器字,并且仅当该字具有可接受的值时才处理相应的数据。