130

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

这是在 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)

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

4

5 回答 5

206

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

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

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

import time
while True:
    time.sleep(1)

现在它将保持 print 'first' 和 'second' 直到你点击Ctrl+ C

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

于 2012-08-05T11:30:20.370 回答
8

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

于 2012-08-05T11:25:21.570 回答
7

我认为最好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()
于 2019-04-03T18:38:58.840 回答
1

@Thomas K 答案的改进版本:

  • is_any_thread_alive()根据这个要点定义一个辅助函数,它可以自动终止main()

示例代码:

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)
于 2020-04-24T15:17:18.637 回答
0

要提防一个简单的“陷阱”,您确定CAPS LOCK没有启用吗?

我在 Pi4 上的 Thonny IDE 中运行 Python 脚本。使用CAPS LOCKon,Ctrl++被传递到键盘缓冲区,而不是Shift+ 。CCtrlC

于 2021-03-16T17:18:47.233 回答