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")
关键修改说明
- 信号阻塞:用
signal.sigprocmask(signal.SIG_BLOCK, ...)把SIGCHLD和SIGINT加入进程信号掩码,这样信号到达时不会被默认处理,而是被挂起等待sigwait获取。 - 子进程收割:捕获到
SIGCHLD后调用os.waitpid(pid, 0),回收子进程的资源,避免出现僵尸进程。 - 信号名称打印:把收到的信号转换成可读名称,方便调试。
现在运行这段代码,子进程3秒后退出时,sigwait会立刻捕获到SIGCHLD并返回,不会再出现死锁的情况啦。
备注:内容来源于stack exchange,提问作者Bence
相关产品推荐
相关产品推荐

