Python 之 捕获 ctrl+c 结束多线程程序
最近工作中有个需求, 写一个 Python 脚本, 运行后需要响应 ctrl+c 的组合键来结束进程。
由于我的程序中创建了别的程序中的实例, 并给了回调函数, 导致它变成了一个多线程的程序。 当想要使用 ctrl+c 结束该程序的时候, 它根本不响应这组合键。
如果使用 ctrl+z 它倒是可以响应, 看着也像是结束了这个程序的运行, 但是使用 ps 一查, 该进程并没有结束, 而是被切换到了后台运行, 使用 ps -T 可以看到它有多个线程, 使用 fg 还可以将其从后台运行给切回来。
在网上找了很多资料和博客, 绝大多数的说法都是给一个全局 Boolean 类型变量, 然后将多线程设置为守护模式, 还需要使用 single 发送信号去修改这个全局变量, 其他的线程响应这个全局变量, 最后完成结束这个程序的目标。
但是我的程序的问题在于, 由于其他的线程不是我主动创建的, 无法在其运行前设置其为守护模式, 所以这种方式的基本条件对于我的程序并不成立。
最终我终于找到了一个 博客, 可以彻底的结束多线程的 Python 进程, 记录一下。
在代码中新增一个类:
class Watcher():
# 解决使用 ctrl+c 不能杀死程序的问题
def __init__(self):
self.child = os.fork()
if self.child == 0:
return
else:
self.watch()
def watch(self):
try:
os.wait()
except KeyboardInterrupt:
self.kill()
os._exit(0)
def kill(self):
try:
os.kill(self.child, signal.SIGKILL)
except OSError:
pass
然后, 在程序运行伊始便创建一个 Watcher 的实例:
if __name__ == "__main__":
Watcher()
do_anything_you_want()
这样, 在程序的运行过程中, 可以随时响应 ctrl+c 的键盘输入, 然后彻底的结束该程序的运行。 它的原理是:用另外一个进程来接受信号后杀掉执行任务进程。
原博客中, watch() 方法中的退出使用的是 sys.exit(), 我试过还是退不出去, 就换成了 os._exit(0) 的方式进行退出。