python 2.6.x theading/signals/atexit在某些版本上失败了吗?

los*_*ode 5 python multithreading signals atexit

我已经看到了很多与此相关的问题...但我的代码适用于python 2.6.2并且无法在python 2.6.5上运行.我错误地认为整个atexit"通过这个模块注册的功能在程序被信号杀死时不被调用"这件事不应该在这里计算,因为我正在捕捉信号然后干净地退出?这里发生了什么?什么是正确的方法来做到这一点?

import atexit, sys, signal, time, threading

terminate = False
threads = []

def test_loop():
    while True:
        if terminate:
            print('stopping thread')
            break
        else:
            print('looping')
            time.sleep(1)

@atexit.register
def shutdown():
    global terminate
    print('shutdown detected')
    terminate = True
    for thread in threads:
        thread.join()

def close_handler(signum, frame):
    print('caught signal')
    sys.exit(0)

def run():
    global threads
    thread = threading.Thread(target=test_loop)
    thread.start()
    threads.append(thread)

    while True:
        time.sleep(2)
        print('main')

signal.signal(signal.SIGINT, close_handler)

if __name__ == "__main__":
    run()
Run Code Online (Sandbox Code Playgroud)

python 2.6.2:

$ python halp.py 
looping
looping
looping
main
looping
main
looping
looping
looping
main
looping
^Ccaught signal
shutdown detected
stopping thread
Run Code Online (Sandbox Code Playgroud)

python 2.6.5:

$ python halp.py 
looping
looping
looping
main
looping
looping
main
looping
looping
main
^Ccaught signal
looping
looping
looping
looping
...
looping
looping
Killed <- kill -9 process at this point
Run Code Online (Sandbox Code Playgroud)

2.6.5上的主线程似乎永远不会执行atexit函数.

Gle*_*ard 8

这里的根本区别实际上与信号和atexit无关,而是与行为的变化无关sys.exit.

在2.6.5之前,sys.exit(更准确地说,SystemExit被捕获在顶层)会导致解释器退出; 如果线程仍在运行,它们将被终止,就像POSIX线程一样.

在2.6.5左右,行为发生了变化:sys.exit现在的效果与从程序的主函数返回的效果基本相同.当你这样做 --in两个版本-所有线程的解释等待退出之前加入.

相关的变化是Py_Finalize现在呼叫wait_for_thread_shutdown()靠近顶部,而不是之前.

这种行为改变似乎是不正确的,主要是因为它不再像记录的那样起作用,简单地说就是:"退出Python".实际效果不再是退出Python,而只是退出线程.(作为旁注,sys.exit当从另一个线程调用时,从未退出Python,但是从记录的行为中隐藏出来的晦涩难度并不能证明更大的一个.)

我可以看到新行为的吸引力:而不是两种退出主线程的方法("退出并等待线程"和"立即退出"),只有一种,因为sys.exit基本上与简单地从顶级功能.然而,这是一个突破性的变化,并且与记录在案的行为背道而驰,远远超过了这一点.

由于这种变化,在sys.exit上面的信号处理程序之后,解释器会等待线程退出,然后atexit在它们执行后运行处理程序.因为它是处理程序本身告诉线程退出,结果是死锁.