问题:无法使用Ctrl-C终止Python脚本
我正在使用以下脚本测试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被如此持久地忽略?我该如何解决?
回答 0
Ctrl+ C终止主线程,但是因为您的线程不在守护程序模式下,所以它们继续运行,并且使进程保持活动状态。我们可以使它们成为守护进程:
f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()
但是,还有另一个问题-一旦主线程启动了线程,就别无他法了。因此它退出了,线程立即被销毁。因此,让主线程保持活动状态:
import time
while True:
time.sleep(1)
现在它将保留打印“ first”和“ second”,直到您按Ctrl+ 为止C。
编辑:正如评论者所指出的,守护进程线程可能没有机会清理临时文件之类的东西。如果需要,请抓住KeyboardInterrupt
主线程并协调其清理和关闭。但是在很多情况下,让守护线程突然死掉可能已经足够了。
回答 1
KeyboardInterrupt和信号仅在进程(即主线程)中可见…看看Ctrl-c即KeyboardInterrupt杀死python中的线程
回答 2
我认为最好在您希望线程死亡时在线程上调用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()
回答 3
@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)