多i线程编程中,常常遇到的1个头痛问题是,主线程退出后,子线程未能正常退出,造成一些数据丢失,文件破坏的隐患,或者成为僵尸进程,占用系统资源。
前面文章介绍了几种优雅关闭线程的方法,但也有一些网友提出疑问:是否可以暴力但不留隐患杀死线程?, 答案是:Yes!
解决方法说明:
1)所谓暴力就是按 Ctrl+C
, 或者 Linux下发送kill -9
强制中止程序信号等。
2)通过python的signal
模块,可以实时捕捉到Ctrl+C信号,并触发回调函数。将开关变量置为关闭,执行clean code,再关闭线程。Linux系统下,将信号 signal.SIGTERM
改为 signal.SIGKILL
即可,用kill -9
命令直接杀死线程。
3)为了让代码更健壮,使用了自定义异常类来负责主线程的退出。
下面是完整代码,在win10下测试,支持按Ctrl+C键, 或者通过任务面板关闭进程,均可安全地关闭线程,杜绝隐患。
from math import e
import time
import threading
import signal
class Task(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
# shutdown_flag 用于关闭线程
self.shutdown_flag = threading.Event()
# ... Other thread setup code here ...
def run(self):
print('Thread #%s started' % self.ident)
while not self.shutdown_flag.is_set():
# 线程代码可以放在这里
print(f"Thread #{self.ident} is running...")
time.sleep(1)
# ... Clean code put here ...
print('Thread #%s stopped' % self.ident)
class ServiceExit(Exception):
"""
自定义1个异常类,用于退出线程
"""
def __init__(self,message="force to quit"):
self.message = message
super(ServiceExit,self).__init__(self.message)
# __str__ is to print() the message
def __str__(self):
return(repr(self.message))
def handler_quit(signum, frame):
"""信号处理函数"""
print('Caught signal %d' % signum)
raise ServiceExit("当前线程被强制退出...")
def main():
# 注册信号回调函数
signal.signal(signal.SIGTERM, handler_quit)
signal.signal(signal.SIGINT, handler_quit)
print('Starting main program')
# Start the sub threads
try:
t1 = Task()
t2 = Task()
t1.start()
t2.start()
# 保持主线程运行,否则无法收到信号
while True:
time.sleep(0.5)
except ServiceExit as e:
t1.shutdown_flag.set()
t2.shutdown_flag.set()
# Wait for the threads to close...
t1.join()
t2.join()
print(e.message)
print('Exiting main program')
if __name__ == '__main__':
main()
运行output 如下
Starting main program
Thread #119072 started
Thread #119072 is running...
Thread #119076 started
Thread #119076 is running...
Thread #119076 is running...
Thread #119072 is running...
Thread #119072 is running...
Thread #119076 is running...
Thread #119076 is running...
Thread #119072 is running...
Caught signal 2
Thread #119072 stopped
Thread #119076 stopped
当前线程被强制退出...
Exiting main program