然而

然而

在模仿 MacOS 终端的open命令或 Window 终端的命令时start,注释这个答案建议将 stdout 和 stderr 附加到~/.xsession-errors,例如 ( bash):

alias open='&>>~/.xsession-errors xdg-open'

我预见到的问题是竞争条件。lsof ~/.xsession-errors显示有 22 个进程打开文件进行写入。

如何防止两个进程写入相同的偏移量~/.xsession-errors

答案1

当以追加模式打开文件时,操作系统保证所有写入都发生在末尾。因此,来自一个写入器的数据不会覆盖来自另一写入器的数据。

>>这只适用于以追加模式(即在 shell 中)打开文件的情况。如果文件的创建者使用以下命令打开它,>则该保证将不适用,并且可能具有以下顺序:

  • 过程1 >out:;现在在位置 0
  • 过程2 >>out:;现在在位置 0
  • 进程 1:写入hello,现在位于位置 6
  • 进程 2: write world,这被写入位置 6,进程 2 现在位于位置 12
  • 进程1: write oops,这是在位置6写入的,因为进程1的文件位置没有改变。

在 Debian 上(自 2001 年左右),该文件.xsession-errors由 `/etc/X11/Xsession 创建,并以追加模式打开,因此一切正常:

 exec >>"$ERRFILE" 2>&1

我不知道登录到~/.xsession-errors.

只要每个人都以附加模式打开文件,所有输出都会出现。然而,输出可能是碎片化的。实际上,对常规文件的足够小的写入是原子的。任何小于 512B 的东西在任何地方都应该足够小,而且我认为 Linux 保证的不仅仅是这个。因此,即使有多个并发编写器,每个日志行也应该显示完整,假设编写器使用行缓冲输出并且行不是太长。

1请注意,POSIX 不保证除管道之外的任何内容。

答案2

使用>>POSIX shell 保证文件将被打开O_APPEND

The Open Group 基本规范第 7 期状态:

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

POSIX 定义了可以的最小字节数要求的写在一个单一的write(2)称呼 (SSIZE_MAX= 32,767)。返回值是实际写入的字节数(保证原子性)。

然而

并非所有文件系统都符合。从多个进程追加到文件说:

需要注意的是,并非所有文件系统都兼容 POSIX。两个著名的例子是 NFS 和 Hadoop 分布式文件系统 (HDFS)。在这些网络文件系统上,追加是模拟的并且受到竞争条件的影响。

不是每个人都玩得好

虽然您可以使用 打开O_APPEND,但写入该文件的其他进程可能不会。您可以检查任何给定的文件:

lsof +fg <file>

令人担忧的是,当我跑步时lsof +fg ~/.xsession-errors,我看到 AP(append) 标志,表明我的列表中的 22 个进程(基于 Arch 的 Manjaro Linux)没有安全地打开文件。

仅当我cat >> ~/.xsession-errors在另一个 shell 中运行时,最终输出行才会包含该AP标志:

cat       3099 ravi    1w   REG   W,AP,LG   0,48      963 1926479 .xsession-errors

如果有人知道应该在上游哪里提出这个问题,请发表评论。

几乎

如果所有进程都使用以下任一方式在本地打开文件:

  • open(2)和旗帜O_APPEND
  • fopen(3)"a"旗帜
  • POSIXsh >>或者bash &>>

那么任何数据都不应该通过竞争条件被覆盖。

谢谢@吉尔斯回答为我指明了正确的方向。

相关内容