You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python使用sigwait监听SIGCHLD信号:子进程终止时函数无法返回的问题

Python使用sigwait监听SIGCHLD信号:子进程终止时函数无法返回的问题

我明白你遇到的困扰了——想用os.sigwait同时等待外部信号触发或者子进程退出,但子进程结束后sigwait却一直卡住,根本不返回对吧?咱们先来拆解问题出在哪,再给出解决办法。

问题根源

sigwait的工作机制有个关键前提:你要等待的信号必须先被阻塞(加入进程的信号掩码)。如果信号没有被阻塞,当信号产生时,系统会直接用默认逻辑处理它:

  • 对于SIGCHLD,默认行为是忽略,系统会自动“收割”子进程,这个信号根本不会被sigwait捕获到;
  • 对于SIGINT,默认是终止进程,同样轮不到sigwait处理。

你的代码里完全没做信号阻塞的操作,所以子进程退出时发送的SIGCHLD直接被系统忽略了,sigwait自然会一直死锁等待。

修复后的代码

我们只需要在调用sigwait前,先把目标信号加入信号掩码阻塞起来,同时处理子进程退出后的收割工作(避免僵尸进程):

#!/usr/bin/env python3
import signal
import os
import time

if __name__ == '__main__':
    pid = None  # initial value

    try:
        pid = os.fork() # method is available only on UNIX platforms

        if pid != 0:  # parent
            # 第一步:先阻塞要等待的信号,让它们被sigwait捕获
            signal.sigprocmask(
                signal.SIG_BLOCK,
                {signal.SIGCHLD, signal.SIGINT}
            )
            # 等待信号触发
            received_sig = signal.sigwait({signal.SIGCHLD, signal.SIGINT})
            print(f"Got signal: {signal.Signals(received_sig).name}")
            
            # 如果是SIGCHLD,收割子进程防止僵尸
            if received_sig == signal.SIGCHLD:
                os.waitpid(pid, 0)

        else:  # child
            print("Child running, will exit after 3s")
            time.sleep(3)
            print("Child exiting")

    finally:
        if pid is None: # fork failed
            print("Fork failed!")
        elif pid == 0:
            print("Child cleaning up")
        else:
            print("Parent cleaning up")

关键修改说明

  1. 信号阻塞:用signal.sigprocmask(signal.SIG_BLOCK, ...)把SIGCHLD和SIGINT加入进程信号掩码,这样信号到达时不会被默认处理,而是被挂起等待sigwait获取。
  2. 子进程收割:捕获到SIGCHLD后调用os.waitpid(pid, 0),回收子进程的资源,避免出现僵尸进程。
  3. 信号名称打印:把收到的信号转换成可读名称,方便调试。

现在运行这段代码,子进程3秒后退出时,sigwait会立刻捕获到SIGCHLD并返回,不会再出现死锁的情况啦。

备注:内容来源于stack exchange,提问作者Bence

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:02:57