You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UNIX中write操作是否原子?pread/pwrite原子性原理疑问

关于UNIX文件I/O原子性的几个问题解答

嘿,刚好对APUE里这段内容很熟悉,来给你拆解清楚这些问题:

1. CPU会不会在write执行中途切换?write是原子操作吗?

首先明确:CPU确实可能在进程执行过程中切换,但write系统调用的原子性取决于你写入的数据大小和目标文件类型。

对于常规磁盘文件来说:

  • 当你写入的数据量小于等于PIPE_BUF(通常是4096字节,不同系统可能有差异)时,内核会保证这个write操作是原子的——也就是说,内核会一次性把所有数据写入文件,不会在中途被其他进程的write打断。所以你说的线程A写"aaaaa"、线程B写"bbbbb"的场景,因为数据量远小于PIPE_BUF,最终结果只会是aaaaabbbbb或者bbbbbaaaaa,绝对不会出现aabbbbbaaa这种交错的情况。
  • 但如果写入的数据量超过PIPE_BUF,内核会把写入拆分成多次完成,这时候就可能被其他进程的write打断,出现字节交错的情况。

另外要注意:write是系统调用,进入内核态后,内核会负责调度和保证符合条件的原子性,用户进程不用操心这部分的同步。

2. pread/pwrite的原子性是怎么实现的?

首先要搞清楚:pread和pwrite的原子性,指的是*「指定偏移量」+「读/写操作」这两个动作是原子的*,而不是说读/写本身的原子性(读/写本身的原子性还是遵循上面说的PIPE_BUF规则)。

它们的原子性不是通过用户态的mutex或lock实现的,而是内核层面直接提供的保证:

  • 当你调用pwrite(fd, buf, len, offset)时,内核会直接使用你传入的offset作为读写位置,并且不会修改文件描述符的当前偏移量。整个过程是一次性完成的,不会出现像lseek+write那样,两个系统调用之间被其他进程打断的情况。
  • 举个例子:如果两个进程同时用pwrite写入同一个文件的不同偏移位置,它们的操作不会互相干扰;如果都写同一个偏移位置,那后执行的会覆盖先执行的,但每个pwrite的写入动作本身还是符合原子性规则的。

回到你最开始的代码问题:那段lseek+write的逻辑在多进程下出问题,就是因为两个系统调用之间可能被内核调度打断,导致其他进程先写入文件,当前进程再写入时就不是追加到原来的末尾了。如果要实现原子追加,除了用pwrite(需要自己获取正确的偏移量,不过其实更推荐的是用O_APPEND标志打开文件,这时候write会自动原子性地追加到文件末尾)。

内容的提问来源于stack exchange,提问作者choxsword

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:46:02