如果同时通过2个不同的进程在同一文件上调用写入系统调用会发生什么情况

操作系统是否正确处理?

或者我将不得不打电话给flock()?

尽管操作系统不会崩溃,文件系统也不会被破坏,但是对write()调用是不可原子化的,除非所描述的文件描述符是一个管道,并且要写入的数据量是PIPE_MAX字节或更少。 标准的相关部分:

尝试写入管道或FIFO有几个主要特点:

  • 原子/非原子:如果在一个操作中写入的全部数据不与来自任何其他进程的数据交错,则写入是原子的。 当有多个写入者将数据发送到一个阅读器时,这非常有用。 应用程序需要知道有多大的写请求可以预期原子执行。 这个最大值被称为{PIPE_BUF}。 IEEE Std 1003.1-2001的这一卷没有说明大于{PIPE_BUF}字节的写入请求是否是原子的,但要求{PIPE_BUF}或更少字节的写入是原子的。

[…]

因此,原则上,您必须同时锁定作者,否则您的书面数据可能会混乱起来(即使在同一个写作中),或者可能有多个写入相互覆盖。 但是,有一个例外 – 如果您通过O_APPEND ,您的写入将是有效的原子:

如果设置了文件状态标志的O_APPEND标志,则在每次写入之前,文件偏移量应设置为文件末尾,在改变文件偏移量和写入操作之间不得进行中间文件修改操作。

虽然这对于非O_APPEND写入或同时读取来说不一定是原子的,但如果所有编写者都使用O_APPEND ,并且在进行read之前以某种方式同步,则应该没问题。

write (和writev ,也)保证原子性。

这意味着如果两个线程或进程同时写入,则不能保证哪一个先写入。 但是,您确实保证系统调用中的任何内容不会与来自另一个系统的数据混合在一起。

到目前为止,它总能正常工作 ,但不一定像你所期望的那样(如果你假设过程A在过程B之前)。

当然,内核会正确处理它,因为内核的正确性 – 根据定义是正确的。

如果你有一套相互配合的植物,那么你可以使用内核来排队。 但请记住,群集与I / O无关:它不会阻止其他人写入文件。 它最多只会干扰其他的植物。

当然,它会正常工作。 它不会使操作系统或进程崩溃。

无论是否有意义,取决于应用程序的写法和文件的用途。

如果文件被所有进程打开为只附加文件,则每个进程(在概念上)在每次写入之前进行原子查找到结束; 这些保证不会覆盖彼此的数据(但当然,顺序是不确定的)。

在任何情况下,如果您使用一个可能会将单个逻辑写入分割为多个写入系统调用的库,那么可能会遇到麻烦。

write()writev()read()readv()可以生成部分写入/读取,其中传输的数据量小于请求的数量。

引用writev()的Linux手册页:

请注意,成功调用传输的字节数少于所请求的字节数不是错误

引用POSIX手册页:

如果write()在成功写入一些数据后被一个信号中断,它将返回写入的字节数。

AFAIU, O_APPEND在这方面没有帮助,因为它不能防止部分写入:它只确保写入的任何数据都被附加在文件末尾。

从Linux内核查看这个错误报告 :

一个进程正在向该文件写入消息。 写入可以分成两部分。 所以如果信号到达,写入被中断。 就spec(POSIX,SUS,…)而言,这是完全有效的行为

FIFO和PIPE写入小于PIPE_MAX但保证是原子的。