【发布时间】:2011-11-06 09:07:10
【问题描述】:
操作系统是否正确处理它?
或者我必须调用flock()吗?
【问题讨论】:
-
什么是“正确”?你预计会发生什么?
标签: c linux operating-system system-calls
操作系统是否正确处理它?
或者我必须调用flock()吗?
【问题讨论】:
标签: c linux operating-system system-calls
虽然操作系统不会崩溃,文件系统也不会损坏,但对write() 的调用不保证是原子的,除非相关文件描述符是管道,并且要写入的数据量为PIPE_MAX 字节或更少。 the standard的相关部分:
尝试写入管道或 FIFO 有几个主要特征:
- 原子/非原子:如果在一个操作中写入的全部量未与来自任何其他进程的数据交错,则写入是原子的。当有多个写入器向单个读取器发送数据时,这很有用。应用程序需要知道可以以原子方式执行的写入请求有多大。此最大值称为 {PIPE_BUF}。本卷 IEEE Std 1003.1-2001 并未说明超过 {PIPE_BUF} 字节的写入请求是否是原子的,但要求 {PIPE_BUF} 或更少字节的写入应该是原子的。
[...]
因此,原则上,您必须同时锁定写入者,否则您写入的数据可能会混淆和乱序(即使在同一写入中),或者您可能有多个写入相互覆盖。但是,有一个例外 - 如果您通过 O_APPEND,您的写入将是有效的原子:
如果设置了文件状态标志的 O_APPEND 标志,则文件偏移量应在每次写入之前设置为文件末尾,并且在更改文件偏移量和写入操作之间不应发生中间文件修改操作。
虽然这对于非O_APPEND 写入或同时读取而言不一定是原子的,但如果所有写入者都使用O_APPEND,并且您在执行read 之前以某种方式同步,那么您应该没问题。
【讨论】:
O_APPEND 使写入原子化。您的所有引用都说写入将始终发生在文件末尾。使用O_APPEND 同时写入的两个进程不会破坏彼此的写入,但它们仍然可以交错出现。
write 可以被信号中断(包括不可阻塞的 SIGSTOP),虽然这不会给出 EINTR,除非你设置了一个非重启的信号处理程序,它会导致写入返回,如果它已经完成了部分写入。因此,您无法确保原子性。即使没有信号,write 和 O_APPEND 也应该被视为由 N 较小的写入组成,每个写入都遵循查找和写入之间的原子性条件,但相对于彼此。
write(以及writev)保证原子性。
这意味着如果两个线程或进程同时写入,您无法保证哪个线程或进程先写入。 但是您确实可以保证,一个系统调用中的任何内容都不会与另一个系统调用中的数据混合。
只要它总是正确地工作,但不一定按照你期望的方式(如果你假设进程 A 在进程 B 之前)。
【讨论】:
write 和 writev 保证原子性仅适用于写入小于 PIPE_MAX 的管道或 FIFO,我相信 - 除非您另有引用?
writev 的写法(没有搜索write 的写法):"readv() 和 writev() 执行的数据传输是原子的:由 writev() 写入的数据被写入为单个块,不会与其他进程中写入的输出混合(但请参阅 pipe(7) 了解异常)"
当然,内核会正确处理它,因为内核的正确性理念——根据定义,它是正确的。
如果您有一组合作的植绒机,那么您可以使用内核将每个人排队。但请记住,flock 与 I/O 无关:它不会阻止其他人写入文件。最多只会干扰其他的植绒者。
【讨论】:
是的,它当然会正常工作。它不会使操作系统或进程崩溃。
这是否有意义,取决于应用程序的编写方式以及文件的用途。
如果所有进程都以仅追加方式打开文件,则每个进程(理论上)在每次写入之前都会执行一次原子搜索结束;这些保证不会覆盖彼此的数据(当然,顺序是不确定的)。
在任何情况下,如果您使用的库可能会将单个逻辑写入拆分为多个写入系统调用,则可能会遇到麻烦。
【讨论】:
write()、writev()、read()、readv() 可以在传输的数据量小于请求的数据量时生成部分写入/读取。
引用writev() 的 Linux 手册页:
请注意,成功调用传输的字节数少于请求的字节数并不是错误
引用 POSIX 手册页:
如果write()在成功写入一些数据后被信号中断,它应该返回写入的字节数。
AFAIU, O_APPEND 在这方面没有帮助,因为它不会阻止部分写入:它只确保写入的任何数据都附加到文件末尾。
看到这个bug report from the Linux kernel:
一个进程正在将消息写入文件。 [...] 写入 [...] 可以一分为二。 [...] 因此,如果信号到达 [...],写入将被中断。 [...] 就规范(POSIX、SUS、...)而言,这是完全有效的行为
FIFO 和 PIPE 写入小于 PIPE_MAX,但保证是原子的。
【讨论】: