Python中正确终止子进程:如何让被控硬件复位?
解决Popen终止后硬件未复位的问题
这问题我做硬件控制项目时也碰到过,核心原因是Popen.kill()(或部分平台的terminate())会直接强制终止子进程,不给它执行清理逻辑的机会。要让硬件在子进程终止前复位,咱们可以从这几个方向入手:
1. 让子进程捕获终止信号,执行复位逻辑
如果被调用的Python脚本是你自己写的,最直接的方法是在脚本里注册信号处理函数,当收到终止信号时先复位硬件再退出。
子进程脚本示例:
import signal import sys import time # 替换成你的实际硬件复位逻辑 def reset_hardware(): print("正在停止硬件发送,恢复初始状态...") # 比如调用硬件SDK的停止接口、重置寄存器等操作 def handle_termination(signum, frame): # 收到终止信号时优先执行复位 reset_hardware() sys.exit(0) # 注册信号处理:覆盖常见的终止信号 signal.signal(signal.SIGTERM, handle_termination) # Unix下terminate()发送的信号 signal.signal(signal.SIGINT, handle_termination) # 对应Ctrl+C/Windows的CTRL_C_EVENT # 模拟硬件持续发送的业务逻辑 print("硬件开始发送数据...") while True: print("发送中...") time.sleep(1)
主进程调用的平台差异注意:
- Unix/Linux系统:别用
hardware_process.kill()!它发送的SIGKILL信号无法被捕获,子进程会直接被干掉。改用hardware_process.terminate(),它发送的SIGTERM会触发咱们注册的处理函数。 - Windows系统:
terminate()和kill()都是强制终止,没法捕获。这时候可以用send_signal(signal.CTRL_C_EVENT),但创建子进程时要加creationflags参数,让子进程能收到Ctrl+C信号:
import subprocess import signal hardware_process = subprocess.Popen( ["python", "hardware_script.py"], creationflags=subprocess.CREATE_NEW_PROCESS_GROUP ) # 发送Ctrl+C信号触发子进程的SIGINT处理逻辑 hardware_process.send_signal(signal.CTRL_C_EVENT) hardware_process.wait()
2. 用IPC管道主动通知子进程复位退出
如果信号机制受平台限制不好用,还可以用管道通信的方式,让主进程主动通知子进程“该复位退出了”,这种方法更通用可靠。
主进程代码:
import subprocess import os # 创建匿名管道 read_pipe, write_pipe = os.pipe() # 启动子进程时传递管道读端的文件描述符 hardware_process = subprocess.Popen( ["python", "hardware_script.py", str(read_pipe)], pass_fds=(read_pipe,) # 把管道描述符传递给子进程 ) # 要终止时,往管道写入停止指令 os.write(write_pipe, b"stop") # 等待子进程完成复位并退出 hardware_process.wait() # 关闭管道资源 os.close(read_pipe) os.close(write_pipe)
子进程代码:
import os import sys import time import threading def reset_hardware(): print("正在复位硬件...") # 你的硬件复位逻辑 def hardware_send_loop(): print("硬件开始发送...") while True: print("发送数据中...") time.sleep(1) # 启动硬件发送线程,设为守护线程避免阻塞退出 send_thread = threading.Thread(target=hardware_send_loop) send_thread.daemon = True send_thread.start() # 监听管道,等待主进程的停止指令 pipe_fd = int(sys.argv[1]) pipe = os.fdopen(pipe_fd, "rb") while True: data = pipe.read() if data == b"stop": reset_hardware() sys.exit(0)
3. 额外补充方案
如果你的硬件有独立的电源控制或复位引脚,也可以考虑在主进程终止子进程后,直接通过GPIO/硬件SDK调用独立复位逻辑,不依赖子进程的清理操作。但这种方法需要硬件本身支持独立复位功能。
内容的提问来源于stack exchange,提问作者Faram
相关产品推荐
相关产品推荐

