【问题标题】:Under what condition does a Python subprocess get a SIGPIPE?Python 子进程在什么条件下获得 SIGPIPE?
【发布时间】:2017-01-04 12:58:03
【问题描述】:

我正在阅读关于子进程模块部分中 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]

documentation 还声明

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

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

【问题讨论】:

    标签: python pipe subprocess


    【解决方案1】:

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

    这是因为subprocess 克隆文件句柄(使用os.dup2() function)。将p2 配置为使用p1.stdout 会触发os.dup2() 调用,要求操作系统复制管道文件句柄;副本用于将dmesg 连接到grep

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

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

    【讨论】:

    • @MartijnPieters 为什么p1 仍在写入标准输出?如果 python 真正调用dup2(p1.stdout, PIPE),那么这意味着p1 不应该在任何地方对标准输出进行任何写入。当管道从 p2 的一端关闭时,将发送一个正确的 SIGPIPE。还是 Python 并没有真正调用 dup2,而只是创建了另一个文件描述符,它会在写入 stdout 时写入它?
    • @darksky:Python 调用 dup2(p1.stdout.fileno(), 0) here, so replacing stdin of the child process with the pipe file number. Why does this mean that p1 不应该对标准输出进行任何写入? p1.stdout管道的一端p1 正在写入另一端。 p1.stdout 只是对管道接收端的 Python 进程引用。
    • @darksky: Python在这里调用dup2(p1.stdout.fileno(), 0),所以用管道文件号替换子进程的stdin。为什么这意味着p1 should not be making any writes to stdout? p1.stdout` 是管道的一端,而p1 正在写入另一端。 p1.stdout 只是对管道接收端的 Python 进程引用。
    猜你喜欢
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    • 2021-02-18
    • 2013-11-26
    相关资源
    最近更新 更多