Ctrl-C即KeyboardInterrupt在Python中杀死线程

问题描述 投票:22回答:3

我在某处读到KeyboardInterrupt异常仅在Python的主线程中引发。我还读到在子线程执行时主线程被阻塞。那么,这是否意味着CTRL + C永远不会到达子线程。我尝试了以下代码:

def main():
    try:
        thread = threading.Thread(target=f)
        thread.start()  # thread is totally blocking (e.g., while True)
        thread.join()
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        sys.exit(1)

def f():
    while True:
        pass  # do the actual work

在这种情况下,CTRL + C对执行没有影响。它就像是无法收听信号。我理解这是错误的方式吗?有没有其他方法可以使用CTRL + C杀死线程?

python multithreading kill keyboardinterrupt
3个回答
10
投票

问题是你正在使用thread1.join(),这将导致你的程序等到该线程完成继续。

信号将始终被主进程捕获,因为它是接收信号的信号,它是具有线程的进程。

如你所示,你基本上运行一个没有线程功能的“普通”应用程序,因为你启动1个线程并等到它完成继续。


13
投票

如果你想让主线程在加入时接收CTRL + C信号,可以通过向join()调用添加超时来完成。

以下似乎工作(如果你想要main实际结束,别忘了添加daemon=True):

thread1.start()
while True:
    thread1.join(600)
    if not thread1.isAlive():
        break

2
投票

在Python中,确实只在每个进程的主线程中引发了KeyboardInterrupt异常。但正如其他答案所提到的那样,Thread.join方法阻塞调用线程也是如此,包括KeyboardInterrupt异常。这就是为什么Ctrl + C似乎没有效果:主线程中的执行仍然在thread.join()行被阻止。

因此,对你的问题一个简单的解决方案是首先,向thread.join()添加一个超时参数,并将该调用放在一个循环中,该循环在子线程退出时结束,这样每次超时后都可以引发KeyboardInterrupt异常,其次,生成子线程daemonic,这意味着它的父(这里的主线程)会在它退出时杀死它(只有非守护程序线程没有被杀死但是当它们的父命令退出时才会被连接):

def main():
    try:
        thread = threading.Thread(target=f, daemon=True)  # create a daemon child thread
        thread.start()

        while thread.is_alive():
            thread.join(1)  # join shortly to not block KeyboardInterrupt exceptions
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        sys.exit(1)

def f():
    while True:
        pass  # do the actual work

但是,如果你控制子线程的代码,更好的解决方案是通知子线程优雅地退出(而不是像第一个解决方案那样突然),例如使用threading.Event

def main():
    try:
        event = threading.Event()
        thread = threading.Thread(target=f, args=(event,))
        thread.start()
        event.wait()  # wait forever but without blocking KeyboardInterrupt exceptions
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        event.set()  # inform the child thread that it should exit
        sys.exit(1)

def f(event):
    while not event.is_set():
        pass  # do the actual work
© www.soinside.com 2019 - 2024. All rights reserved.