怎么让Python线程支持excepthook

如何让Python线程支持excepthook
在游戏中,一般会在主线程开始时,设置一个 excepthook,来对程序异常进行特定处理。

每个线程都有自己的栈,只要在发生异常时,能够把自己的调用栈和异常的相关信息,发给特定的异常处理函数(比如用户自定义的函数)处理,就可以实现 excepthook。理论上任何语言实现的线程,都可以实现 excepthook,只是对线程的异常捕获和 excepthook 的实现有要求。在 excepthook 实现中,如果有对资源(比如日志文件)和全局变量的访问,需要做好线程互斥处理。在工作线程中,当发生异常并逐级向上抛时,如果在最上层(工作线程的 main 函数)还没有被捕获,则线程会被异常终止;此时,设置的 excepthook 可能就无法发生作用了。

对 Python 线程而言,需要明确几点:
1,自定义的 excepthook 是赋值给 sys.excepthook 的。
2,程序启动时,bulit-in 的 sys.excepthook 会被保存在 sys.__excepthook__ 中。
3,当工作线程发生异常并被捕获时,如果有用户自定义的 excepthook,就应该交由该函数处理。

再来看 Python 库中 threading.py 的实现,在 Thread.__bootstrap_inner() 函数中,调用 run() 后捕捉的异常,没有对用户自定义的 excepthook 进行判断,也就导致了 Python 线程的 excepthook 无法生效。如果把代码改为如下(...... 表示保持原来的代码不变):

    try:
        self.run()
    except SystemExit:
        ......
    except:
        ......
        if _sys:
        	if id(_sys.excepthook) != id(_sys.__excepthook__):
        		exc_type, exc_value, exc_tb = self.__exc_info()
        		_sys.excepthook(exc_type, exc_value, exc_tb)
        	else:
                _sys.stderr.write("Exception in thread %s:\n%s\n" %
                              (self.getName(), _format_exc()))
        else:
        	......

则在线程中发生异常时,预设的 excepthook 就可以正常生效了。