linux管道原子性写入,write(2)/ read(2)linux中进程之间的原子性

我有一个案例,有两个进程作用于同一个文件 – 一个作为作者,一个作为读者.该文件是一行文本文件,编写器在循环中重写该行.读者读取该行.伪代码如下所示:

作家过程

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个字节.

man page没有说正常文件的原子性,它只提到512字节的管道原子性.

我用tmpfs和ext4尝试了这个,结果是一样的.使用O_SYNC,ext4写入变为原子并且我理解它,因为写入在它到达磁盘之前不会返回,但是O_SYNC对tmpfs(/ dev / shm)没有帮助.

解决方法:

POSIX不对read和write的原子操作提供任何最低保证,除了在管道上写入(其中写入高达PIPE_BUF(≥512)字节保证是原子的,但读取没有原子性保证).读取和写入操作以字节值描述;除了管道之外,与围绕单字节写操作的循环相比,写操作不提供额外的保证.

我不知道Linux会给出任何额外的保证,无论是16还是512.在实践中,我希望它依赖于内核版本,文件系统,以及可能还有其他因素,如底层块设备, CPU数量,CPU架构等

O_SYNC,O_RSYNC和O_DSYNC保证(synchronized I/O data integrity completion,在POSIX的可选SIO功能中读取和写入)不是您所需要的.它们保证在读取或写入系统调用之前将写入提交到持久存储,但不对在读取操作正在进行时启动的写入做出任何声明.

在您的方案中,读取和写入文件看起来不像正确的工具集.

>如果您只需要传输少量数据,请使用管道.不要过于担心复制:在大多数处理或上下文切换的规模上复制内存中的数据非常快.另外Linux非常适合优化副本.

>如果需要传输大量数据,则应该使用某种形式的内存映射:如果不需要磁盘支持,则为共享内存段;如果是,则为mmap.这并不能神奇地解决原子性问题,但可能会提高正确同步机制的性能.要执行同步,有两种基本方法:

>生产者将数据写入共享内存,然后向消费者发送通知,准确指出可用的数据.消费者仅根据请求处理数据.通知可以使用相同的信道(例如mmap msync)或不同的信道(例如管道).

>生产者将数据写入共享内存,然后刷新写入(例如msync).然后,生产者将一个众所周知的值写入一个机器字(sig_atomic_t通常会起作用,即使其原子性仅在信号上正式保证 – 或者,实际上是uintptr_t).消费者读取一个机器字,并且只有当该字具有可接受的值时才处理相应的数据.

标签:filesystems,linux,tmpfs

来源: https://codeday.me/bug/20190623/1270109.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值