Linux 无法使用 Ctrl-C 杀死 Python 脚本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11815947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:00:47  来源:igfitidea点击:

Cannot kill Python script with Ctrl-C

pythonlinux

提问by dotancohen

I am testing Python threading with the following script:

我正在使用以下脚本测试 Python 线程:

import threading

class FirstThread (threading.Thread):
    def run (self):
        while True:
            print 'first'

class SecondThread (threading.Thread):
    def run (self):
        while True:
            print 'second'

FirstThread().start()
SecondThread().start()

This is running in Python 2.7 on Kubuntu 11.10. Ctrl+Cwill not kill it. I also tried adding a handler for system signals, but that did not help:

这是在 Kubuntu 11.10 上的 Python 2.7 中运行的。Ctrl+C不会杀死它。我还尝试为系统信号添加一个处理程序,但这没有帮助:

import signal 
import sys
def signal_handler(signal, frame):
    sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

To kill the process I am killing it by PID after sending the program to the background with Ctrl+Z, which isn't being ignored. Why is Ctrl+Cbeing ignored so persistently? How can I resolve this?

为了终止进程,我在使用Ctrl+将程序发送到后台后通过 PID 终止它Z,这不会被忽略。为什么Ctrl+C如此顽固地被忽视?我该如何解决这个问题?

采纳答案by Thomas K

Ctrl+Cterminates the main thread, but because your threads aren't in daemon mode, they keep running, and that keeps the process alive. We can make them daemons:

Ctrl+C终止主线程,但由于您的线程未处于守护程序模式,因此它们会继续运行,从而使进程保持活动状态。我们可以让它们成为守护进程:

f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()

But then there's another problem - once the main thread has started your threads, there's nothing else for it to do. So it exits, and the threads are destroyed instantly. So let's keep the main thread alive:

但是还有另一个问题 - 一旦主线程启动了您的线程,它就没有其他事情可做。所以它退出,线程立即被销毁。所以让我们保持主线程活着:

import time
while True:
    time.sleep(1)

Now it will keep print 'first' and 'second' until you hit Ctrl+C.

现在它将保持打印“第一”和“第二”,直到您点击Ctrl+ C

Edit:as commenters have pointed out, the daemon threads may not get a chance to clean up things like temporary files. If you need that, then catch the KeyboardInterrupton the main thread and have it co-ordinate cleanup and shutdown. But in many cases, letting daemon threads die suddenly is probably good enough.

编辑:正如评论者所指出的,守护进程线程可能没有机会清理临时文件之类的东西。如果你需要,然后KeyboardInterrupt在主线程上捕获它并让它协调清理和关闭。但在很多情况下,让守护线程突然死亡可能就足够了。

回答by Jon Clements

KeyboardInterrupt and signals are only seen by the process (ie the main thread)... Have a look at Ctrl-c i.e. KeyboardInterrupt to kill threads in python

KeyboardInterrupt 和信号只能被进程看到(即主线程)...看看Ctrl-c ie KeyboardInterrupt to kill thread in python

回答by Johan Snowgoose

I think it's best to call join() on your threads when you expect them to die. I've taken some liberty with your code to make the loops end (you can add whatever cleanup needs are required to there as well). The variable die is checked for truth on each pass and when it's True then the program exits.

我认为最好在您的线程上调用 join() 当您希望它们死亡时。我对你的代码采取了一些自由来结束循环(你也可以在那里添加任何需要的清理需求)。在每次传递时检查变量 die 是否为真,当它为 True 时,程序退出。

import threading
import time

class MyThread (threading.Thread):
    die = False
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run (self):
        while not self.die:
            time.sleep(1)
            print (self.name)

    def join(self):
        self.die = True
        super().join()

if __name__ == '__main__':
    f = MyThread('first')
    f.start()
    s = MyThread('second')
    s.start()
    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        f.join()
        s.join()

回答by Hansimov

An improved version of @Thomas K's answer:

@Thomas K 答案的改进版本:

  • Defining an assistant function is_any_thread_alive()according to this gist, which can terminates the main()automatically.
  • is_any_thread_alive()根据这个要点定义一个辅助功能,可以main()自动终止。


Example codes:

示例代码:

import threading

def job1():
    ...

def job2():
    ...

def is_any_thread_alive(threads):
    return True in [t.is_alive() for t in threads]

if __name__ == "__main__":
    ...
    t1 = threading.Thread(target=job1,daemon=True)
    t2 = threading.Thread(target=job2,daemon=True)
    t1.start()
    t2.start()

    while is_any_thread_alive([t1,t2]):
        time.sleep(0)