在什么情况下,Python子进程会获得SIGPIPE?
问题内容:
我正在子过程模块部分中阅读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]
该文档还指出
“启动p2之后的p1.stdout.close()调用很重要,如果p2在p1之前退出,则p1会收到SIGPIPE。
为什么在我们收到SIGPIPE之前必须先关闭p1.stdout,如果已经关闭p1,p1如何知道p2在p1之前退出?
问题答案:
SIGPIPE
是一个信号,如果dmesg
尝试写入关闭的管道将被发送。在这里,dmesg
最后有 两个
要写入的目标,即Python进程和该grep
进程。
那是因为subprocess
克隆文件句柄(使用os.dup2()
函数)。配置p2
为使用p1.stdout
会触发一个os.dup2()
调用,要求操作系统复制管道文件句柄。重复用于连接dmesg
到grep
。
对于dmesg
stdout,有两个打开的文件句柄,如果只有 其中一个
提前关闭,dmesg
则永远不会发出SIGPIPE
信号,因此永远不会检测到关闭。会不必要地继续产生产出。 __grep``dmesg
因此,通过p1.stdout
立即关闭,可以确保从dmesg
stdout读取的唯一剩余文件句柄是该grep
进程,并且如果该进程将退出,则会dmesg
收到SIGPIPE
。