多进程信号处理疑问:子进程终止时父进程为何未触发信号处理?
问题:fork上下文下子进程超时未触发父进程信号处理函数?
我原本理解在fork上下文下,传递给子进程的信号会触发父进程的信号处理函数,但以下示例并未出现预期行为:
import time import asyncio from pebble import ProcessPool import multiprocessing SLEEP = 10 TIMEOUT = 2 import signal def function(seconds): print(f"Going to sleep {seconds}s..") time.sleep(seconds) print(f"Slept {seconds}s.") def stop(reaons:str="caught signals"): print("stopping") async def main(): loop = asyncio.get_running_loop() pool = ProcessPool(2, context=multiprocessing.get_context("fork")) loop.add_signal_handler(signal.SIGINT, stop) loop.add_signal_handler(signal.SIGTERM, stop) try: fut = pool.schedule(function, (SLEEP,), timeout=TIMEOUT) await asyncio.wrap_future(fut, loop=loop) except asyncio.exceptions.TimeoutError: print("caught exception") if __name__ == '__main__': asyncio.run(main())
运行输出:
Going to sleep 10s.. caught exception
我原本预期这会触发父进程的stop信号处理函数,请问这是为什么?
回答
核心原因有两点:
你误解了fork上下文的信号传递逻辑
fork创建的子进程会继承父进程的信号处理函数,但子进程收到信号时,是在子进程自身的进程空间执行该处理函数,而非触发父进程的信号处理函数。不存在“子进程收到信号会触发父进程handler”的机制。pebble的超时机制不依赖向父进程发信号
你的代码里的TimeoutError是pebble库内部的异步超时通知:当任务超时,pebble会主动终止子进程(可能向子进程发送终止信号),但这个过程中不会向父进程发送SIGINT或SIGTERM信号。父进程捕获的TimeoutError只是库封装的异常,和信号处理完全无关,自然不会触发你注册的stop函数。
如果想在任务超时后执行stop逻辑,不需要依赖信号,直接在except TimeoutError代码块里调用stop()即可。
内容的提问来源于stack exchange,提问作者nz_21
相关产品推荐
相关产品推荐

