Python 子进程在什么情况下会获得 SIGPIPE?

use*_*990 3 python subprocess pipe

我正在阅读子流程模块部分中有关 Popen 类的 Python 文档,我遇到了以下代码:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]
Run Code Online (Sandbox Code Playgroud)

文件还指出

“启动 p2 后的 p1.stdout.close() 调用很重要,如果 p2 在 p1 之前退出,p1 会收到 SIGPIPE。

为什么必须在我们接收 SIGPIPE 之前关闭 p1.stdout,如果我们已经关闭了 p1,那么 p1 如何知道 p2 在 p1 之前退出?

Mar*_*ers 5

SIGPIPE是一个信号,如果dmesg试图写入一个封闭的管道就会被发送。在这里,dmesg最终有两个目标要写入,您的 Python 进程和grep进程。

那是因为subprocess克隆文件句柄(使用os.dup2()函数)。配置p2使用p1.stdout会触发一个os.dup2()调用,要求操作系统复制管道文件句柄;副本用于连接dmesggrep.

对于dmesgstdout 的两个打开的文件句柄,如果只有其中一个提前关闭,dmesg则永远不会发出SIGPIPE信号,因此永远不会检测到关闭。将不必要地继续生产输出。grepdmesg

因此,通过p1.stdout立即关闭,您可以确保从dmesgstdout读取的唯一剩余文件句柄是grep进程,并且如果该进程要退出,则会dmesg收到SIGPIPE.