python 2.6.x theading/signal/atexit在某些版本上失败? [英] python 2.6.x theading / signals /atexit fail on some versions?

查看:125
本文介绍了python 2.6.x theading/signal/atexit在某些版本上失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到很多与此相关的问题...但是我的代码 2.6.2上工作,而 在python 2.6.5上工作却失败.我是否认为整个atexit当程序被信号杀死时不调用通过此模块注册的功能"是不对的,因为我捕获了信号然后干净地退出了,所以在这里不应该算数吗?这里发生了什么?正确的方法是什么?

I've seen a lot of questions related to this... but my code works on python 2.6.2 and fails to work on python 2.6.5. Am I wrong in thinking that the whole atexit "functions registered via this module are not called when the program is killed by a signal" thing shouldn't count here because I'm catching the signal and then exiting cleanly? What's going on here? Whats the proper way to do this?

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()

python 2.6.2:

python 2.6.2:

$ python halp.py 
looping
looping
looping
main
looping
main
looping
looping
looping
main
looping
^Ccaught signal
shutdown detected
stopping thread

python 2.6.5:

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

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

The main thread on 2.6.5 appears to never execute the atexit functions.

推荐答案

此处的根本区别实际上与信号和atexit均无关,而与sys.exit的行为有关.

The root difference here is actually unrelated to both signals and atexit, but rather a change in the behavior of sys.exit.

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

Before around 2.6.5, sys.exit (more accurately, SystemExit being caught at the top level) would cause the interpreter to exit; if threads were still running, they'd be terminated, just as with POSIX threads.

在2.6.5左右,行为已更改:sys.exit的效果现在与从程序主函数返回的效果基本相同.当您在两个版本中都执行那个时,解释器将等待所有线程加入后退出.

Around 2.6.5, the behavior changed: the effect of sys.exit is now essentially the same as returning from the main function of the program. When you do that--in both versions--the interpreter waits for all threads to be joined before exiting.

相关的更改是,Py_Finalize现在在顶部附近调用了wait_for_thread_shutdown(),以前没有.

The relevant change is that Py_Finalize now calls wait_for_thread_shutdown() near the top, where it didn't before.

这种行为上的改变似乎是不正确的,主要是因为它不再像所记录的那样起作用,即:从Python退出".实际的效果不再是退出Python,而仅仅是退出线程. (作为一个补充说明,sys.exit从未在从另一个线程调用时退出过Python,但是与已记录的行为的明显歧义并不能证明更大的理由.)

This behavioral change seems incorrect, primarily because it no longer functions as documented, which is simply: "Exit from Python." The practical effect is no longer to exit from Python, but simply to exit the thread. (As a side note, sys.exit has never exited Python when called from another thread, but that obscure divergance from documented behavior doesn't justify a much bigger one.)

我可以看到这种新行为的吸引力:而不是两种退出主线程的方式(退出并等待线程"和立即退出"),只有一种,因为sys.exit本质上与简单地相同从顶部函数返回.但是,这是一个重大变化,与记录在案的行为大相径庭.

I can see the appeal of the new behavior: rather than two ways to exit the main thread ("exit and wait for threads" and "exit immediately"), there's only one, as sys.exit is essentially identical to simply returning from the top function. However, it's a breaking change and diverges from documented behavior, which far outweighs that.

由于此更改,在上面的信号处理程序中,在sys.exit之后,解释器围着等待线程退出,然后在它们运行后运行atexit处理程序.由于是处理程序本身告诉线程退出,因此结果是死锁.

Because of this change, after sys.exit from the signal handler above, the interpreter sits around waiting for threads to exit and then runs atexit handlers after they do. Since it's the handler itself that tells the threads to exit, the result is a deadlock.

这篇关于python 2.6.x theading/signal/atexit在某些版本上失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆