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

时间:2011-08-29 21:59:51

标签: c linux operating-system system-calls

操作系统是否正确处理?

或者我必须调用flock()吗?

5 个答案:

答案 0 :(得分:10)

虽然操作系统不会崩溃,并且文件系统不会被破坏,但对write()的调用 NOT 保证是原子的,除非有问题的文件描述符是管道,要写入的数据量为PIPE_MAX个字节或更少。 the standard的相关部分:

  

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

     
      
  • 原子/非原子:如果在一次操作中写入的总量与来自任何其他进程的数据不交错,则写入是原子的。当有多个写入器将数据发送到单个读取器时,这很有用。应用程序需要知道可以预期以原子方式执行写入请求的大小。此最大值称为{PIPE_BUF}。 IEEE Std 1003.1-2001的这一卷未说明超过{PIPE_BUF}字节的写请求是否是原子的,但要求{PIPE_BUF}或更少字节的写入必须是原子的。
  •   
     

[...]

因此,原则上,您必须使用同时写入程序锁定,否则您的书面数据可能会混淆和乱序(即使在同一次写入中),或者您可能会有多次写入相互覆盖。但是,有一个例外 - 如果你传递O_APPEND,你的写入将是有效的原子:

  

如果设置了文件状态标志的O_APPEND标志,则应在每次写入之前将文件偏移设置为文件的末尾,并且在更改文件偏移和写入操作之间不应进行中间文件修改操作。 / p>

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

答案 1 :(得分:2)

write(以及writev也保证原子性。

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

只要它始终正常工作,但不一定按照您期望的方式(如果您假设流程A出现在流程B之前)。

答案 2 :(得分:1)

当然内核会正确处理它,因为内核的正确性是正确的 - 这在定义上是正确的。

如果你有一套合作的flockers,那么你可以使用内核为每个人排队。但请记住,flock与I / O无关:它不会阻止其他人编写文件。它最多只会干扰其他人。

答案 3 :(得分:1)

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

是否有意义,取决于应用程序的编写方式和文件的目的。

如果文件被所有进程打开为仅附加,则每个进程(在概念上)在每次写入之前执行原子搜索到结束;保证不会覆盖彼此的数据(当然,订单是不确定的)。

在任何情况下,如果您使用的库可能会将单个逻辑写入分成多个写入系统调用,那么就会出现问题。

答案 4 :(得分:0)

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

引用writev()

的Linux手册页
  

请注意,成功调用传输的字节数少于请求的

,这不是错误

引用POSIX手册页:

  

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

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

请参阅此bug report from the Linux kernel

  

进程正在将消息写入文件。 [...]写入[...]可以分为两部分。 [...]因此,如果信号到达,则写入被中断。 [...]就规范(POSIX,SUS,......)而言,这是完全有效的行为

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