无法使用Ctrl-C终止Python脚本

dot*_*hen 109 python linux

我正在使用以下脚本测试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()
Run Code Online (Sandbox Code Playgroud)

这是在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)
Run Code Online (Sandbox Code Playgroud)

为了杀死进程,我在用Ctrl+ 发送程序到后台后通过PID将其杀死Z,这是不被忽略的.为什么Ctrl+ C如此坚持被忽视?我该如何解决这个问题?

Tho*_*s K 171

Ctrl+ C终止主线程,但由于你的线程没有处于守护进程模式,它们会继续运行,并使进程保持活动状态.我们可以让他们成为守护进程:

f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()
Run Code Online (Sandbox Code Playgroud)

但是还有另外一个问题 - 一旦主线程开始你的线程,就没有别的办法了.所以它退出,线程立即被销毁.所以让我们保持主线程的活着:

import time
while True:
    time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

现在它将保持打印"第一"和"第二",直到你达到Ctrl+ C.

编辑:正如评论者指出的那样,守护程序线程可能没有机会清理临时文件之类的东西.如果你需要,那么赶上KeyboardInterrupt主线程并让它协调清理和关闭.但在许多情况下,让守护程序线程突然死亡可能已经足够了.

  • @ThomasK例如,`tempfile.TemporaryFile()`创建的临时文件可能留在磁盘上. (6认同)
  • 你应该提一下,通过这样做,线程没有优雅地停止,一些资源没有被释放. (5认同)
  • 好吧,Ctrl-C 从来都不是停止任何事情的优雅方式。我不确定会留下哪些资源 - 当进程退出时操作系统不应该回收任何东西吗? (3认同)
  • 在python3中看起来[你可以将`daemon = True`](https://docs.python.org/3/library/threading.html#threading.Thread)传递给`Thread .__ init__` (3认同)

Jon*_*nts 8

KeyboardInterrupt和信号只能被进程看到(即主线程)...看看Ctrl-c即KeyboardInterrupt来杀死python中的线程


Joh*_*ose 5

我认为最好在您的线程上调用 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()
Run Code Online (Sandbox Code Playgroud)