如何让子线程在Python中处理主进程被杀或键中断?

时间:2015-06-06 15:25:50

标签: python multithreading

在多线程设计中,我想在程序异常退出时执行一些干净的步骤。正在运行的线程应该清理当前任务然后退出,而不是立即被杀死并留下一些脏数据。我发现使用threading模块无法捕获KeyInterrupt异常。

这是我的测试代码:

#!/usr/bin/env python3

from time import sleep

def do_sth():
    print("I'm doing something...")
    sleep(10)

if __name__ == "__main__":
    do_sth()

当我按KeyInterrupt

时,Python会引发CTRL-c异常
$ Python3 test.py
I'm doing something ... 
^C
Traceback (most recent call last):
File "test.py", line 10, in <module>
do_sth ()
File "test.py", line 7, in do_sth
sleep (10)
KeyboardInterrupt

所以我可以抓住这个例外。

def do_sth ():
    try:
        print ("I'm doing something ...")
        sleep (10)
    except (KeyboardInterrupt, SystemExit):
        print ("I'm doing some clean steps and exit.")

但是当我使用线程模块时,根本不会引发此异常。

#!/usr/bin/env python3

from time import sleep
import threading

def do_sth():
    print("I'm doing something...")
    sleep(10)

if __name__ == '__main__':
    t = threading.Thread(target=do_sth)
    t.start()
    t.join()

结果:

$ python3 test.py
I'm doing something...
^C

正在运行的线程被直接杀死,并且没有异常被引发。

我该如何处理?

1 个答案:

答案 0 :(得分:0)

一种方法是处理KeyboardInterrupt异常。

在这种情况下要做的另一件事是跨所有线程管理应用程序的状态。 其中一个解决方案是在代码中添加对Signals的支持。它可以优雅地处理关闭过程。

以下是一个简单的设置:

class SignalHandler:
    continue_running = True

    def __init__(self):
        signal.signal(signal.SIGUSR2, self.signal_handler)
        signal.signal(signal.SIGTERM, self.signal_handler)
        signal.signal(signal.SIGINT, self.signal_handler)
        logging.info("SignalHandler::Init")

    def signal_handler(self, num, stack):
        logging.warning('Received signal %d in %s' % (num, threading.currentThread()))
        SignalHandler.continue_running = False
        logging.warning("Time to SHUT DOWN ALL MODULES")

所有主题都会尝试利用SignalHandler.continue_running中的状态来确保他们都知道何时停止。 如果有人试图通过调用kill -2 [PID]来杀死这个python进程 - 所有线程都会知道需要关闭。