python 2:守护进程线程不会在KeyboardInterrupt上被杀死

时间:2018-11-29 14:39:26

标签: python multithreading

我正在编写一个简单的线程应用程序,并且将线程设置为daemon,因为我希望我的程序在KeyboardInterrupt退出。这样可以很好地工作,并使用python3可以得到预期的结果,但是python2.7似乎并不尊重daemon标志。下面是我的示例代码

if __name__ == '__main__':
    try:
        threads = [Thread(target=some_func, args=(arg1,arg2)) for _ in range(10)]

        for th in threads:
            th.daemon=True
            th.start()

        for th in threads:
            th.join()
    except KeyboardInterrupt:
        sys.exit('Ctrl-c issued by user .. Exiting')

当我在python3上运行此代码,然后过一会儿按ctrl-c时,我的程序按预期退出,但是当我用python2.7运行此代码,然后按ctrl-c时它永远不会退出,我必须从shell中终止该进程。

我在这里想念什么吗?我还尝试设置threading.Event,然后在发生KeyboardInterrupt时清除事件,但即使这样也不起作用

使用python3,如果我没有join我的daemon线程,则它们将在程序完成后退出,并且如果我不将线程标记为{ {1}}而不是daemon,然后程序继续运行,一旦我按下join,它就会退出。但这与ctrl-c

都不起作用

编辑#1

我做了一些更深入的研究,看来python2.7无法捕获python2.7。这更加奇怪,因为KeyboardInterrupt可以正常工作,它是一个非线程程序,但是即使线程被标记为KeyboardInterrupt,也无法捕获线程KeyboardInterrupt

所有这些仅在daemon上发生,并且python2.7可以正常工作。

3 个答案:

答案 0 :(得分:1)

Thread.join在旧版Python中的工作方式可以静默吞没信号,直到join完成为止。这包括SIGINT aka KeyboardInterrupt。

作为解决方法,您可以尝试短sleepjoin。如果您希望线程自己消失,请确保进行清理:

    while threads:
        threads[-1].join(1)  # allow KeyboardInterrup once per second
        if not threads[-1].is_alive():  # reap dead Threads
           threads.pop()

  

我的第一个想法是使用thread.join,但这似乎阻塞了主进程(忽略KeyboardInterrupt),直到线程完成。1


  

多线程Python程序通常会忽略键盘中断生成的SIGINT,尤其是在获取信号的线程正在等待或休眠的情况下。 2


  

我正在使用Python 2.7,而我的程序在使用时会忽略SIGTERM信号   ThreadPoolExecutor。

     

经过一些调试后,我发现我的主线程在Thread.join()上被阻塞,   并保持中断,直到呼叫返回。 3

答案 1 :(得分:1)

感谢@MisterMiyagi的建议,我能够测试https://stackoverflow.com/a/3788243/5349916中提到的一些解决方案。

请注意,以下解决方案仅适用于daemon线程,因为非守护程序将始终阻塞主程序,直到您将join放在其上完成其工作为止。如果您没有在非守护程序线程上放置join,那么如果您的主线程退出并且它们是预期的行为,它们将继续在后台运行。

我遇到的问题专门针对daemon线程。所以这是解决方案。

#1:不要在线程上加入联接,因为这将导致线程阻塞主进程。之所以有效,是因为daemon线程在主程序退出后立即退出,因此当您不放置join时,您就不会在主程序中等待,并且{{1}中的time.sleep(1) }}只是为了确保while线程继续执行,一旦我按下daemon,main就会退出,ctrl-c线程也会退出。

daemon

#2:如果要在线程上放置if __name__ == "__main__": try: threads = [threading.Thread(name='daemon', target=daemon) for _ in range(8)] for th in threads: th.daemon = True th.start() while True: time.sleep(1) # signal.pause() # This worked fine for me on Linux, on Windows it doesn't work, not sure about Mac. I am not recommending this because of platform dependency. except KeyboardInterrupt: ,请对其使用超时,然后将其保留在join循环中,直到{{1 }}是while。这将继续检查thread列表中的每个线程,直到其存活,然后等待1秒钟执行它。现在,由于alive的条件将变为threads,直到while完成后实际收获为止。它会在1秒的小块时间内阻塞主程序,一旦您按下TrueThread就不再存在,因此主程序退出。

ctrl-c

答案 2 :(得分:-1)

这是由于'th.join()'引起的。这使他们基本上互相等待。您是否尝试过使用类似的东西:

except KeyboardInterrupt:
    for th in threads:
        th._Thread__stop()
    sys.exit('....')

这在重现问题时对我有用。希望对您有所帮助! 另外,如果有更多帮助,请继续阅读此线程(无双关!),因为它提供了一些有用的信息:

Is there any way to kill a Thread?