是什么导致 Unix 进程因管道损坏而终止?

是什么导致 Unix 进程因管道损坏而终止?

以下是我想到的一些选择,不确定哪一个是正确的。

  1. 从管道读取 I/O 错误。
  2. 写入管道另一端的进程因失败而终止。
  3. 所有可以写入管道的进程都已关闭它。
  4. 管道的写入缓冲区已满。
  5. 对等方已关闭双工管道的另一个方向。
  6. 写入失败,因为没有进程可以从管道读取。
  7. 系统调用返回 EPIPE 错误,并且没有安装错误处理程序。

答案1

当进程尝试写入没有剩余读取器的 SOCK_STREAM 类型的管道(命名或未命名)或套接字时,进程会收到 SIGPIPE。

这通常是想要的行为。一个典型的例子是:

find . | head -n 1

您不想在终止find后继续运行head(然后关闭该管道上唯一打开用于读取的文件描述符)。

yes命令通常依赖于该信号来终止。

yes | some-command

将写入“y”直到某个命令终止。

请注意,这不仅是在命令退出时,也是在所有读取器关闭对管道的读取 fd 时。在:

yes | ( sleep 1; exec <&-; ps -fC yes)
      1 2       1        0

在子 shell 显式关闭其 stdin 后,将有 1(子 shell)、2(子 shell + sleep)、1(子 shell)、0 fd 从管道读取,此时yes将收到 SIGPIPE。

上面,大多数 shell 使用pipe(2)whileksh93使用 a socketpair(2),但在这方面的行为是相同的。

当进程忽略 SIGPIPE 时,写入系统调用(通常是write,但也可能是pwrite, send, splice...)会返回错误EPIPE。因此,想要手动处理损坏的管道的进程通常会忽略 SIGPIPE 并根据 EPIPE 错误采取行动。

答案2

(6)

写入失败,因为没有进程可以从管道读取。

尽管除非您复制描述符并分叉,否则只能有一个进程开始:通常一个管道有一个读取器和一个写入器,当其中一个关闭连接时,管道将失效。如果您使用命名管道,则可以与其建立多个连接(串行),但每个连接在这个意义上都代表一个新管道。因此,线程或进程的“管道”与文件描述符同义。

man 7 pipe

如果引用管道读取端的所有文件描述符都已关闭,则 write(2) 将导致为调用进程生成 SIGPIPE 信号。如果调用进程忽略此信号,则 write(2) 会失败并出现错误 EPIPE。

因此,“断管”对于作者来说就像 EOF 对于读者一样。

答案3

当读取进程在写入进程之前退出时,就会发生管道损坏。所以我会选择(6)

相关内容