2017-08-04 85 views
1

我在这里看到了几个关于以干净的方式杀死python线程的线程,但我认为我有一个更基本的问题。假设我有一些代码,看起来像这样:主线程不捕捉KeyboardInterrupt

t1 = threading.Thread(target=method1, args=(args1,)) 
t1.daemon = True 

t2 = threading.Thread(target=method2, args=(args2,)) 
t2.daemon = True 
t1.start() 
t2.start() 

while True: 
    time.sleep(1) 

我想主线程注意到一个按Ctrl-C键盘中断,并从那里我可以处理其他线程的终止(t1t2)视情况而定。但无论我做什么,我都无法获得主线来捕捉KeyboardInterrupt。我已经试过这样的事情:

try: 
    while True: time.sleep(100) 
except KeyboardInterrupt: 
    print "Quitting!" 

或者是这样的:

threads = [] 
threads.append(t1) 
threads.append(t2) 
while len(threads) > 0: 
    try: 
     threads = [t for t in threads if t is not None and t.isAlive()] 
     time.sleep(1) 
    except: 
     print "Ctrl - C received, kiling" 
     for t in threads: 
      t.kill_received = True 

但这些都不即使打印信息的异常处理程序,只显示这一点:

Exception in thread Thread-3: 
Traceback (most recent call last): 
    File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner 
    self.run() 
    File "/usr/local/lib/python2.7/dist-packages/audioread/gstdec.py", line 149, in run 
    self.loop.run() 
    File "/usr/lib/python2.7/dist-packages/gi/overrides/GLib.py", line 576, in run 
    raise KeyboardInterrupt 
KeyboardInterrupt 

这里的主要问题是不是如何安全地杀死t1t2(我必须处理这个问题,最终),但为什么主线程不在这里捕获KeyboardInterrupt

编辑:正如我编写的例子,我已经尝试了在try-except块内的while循环中睡眠的方法。任何其他想法?

+0

这是很神秘,我试图子类'threading.Thread'并从CPython的源为复制的代码'run()'方法,它有一个'try/finally'。我添加了一个'except Exception:',其中带有'print',但是当发生'KeyboardInterrupt'时,它不会被触发。必须有一些更深层次的魔法发生。我认为这可能与线程是守护神的事实有关。 – martineau

+0

对于它的价值,我也尝试了将守护程序属性设置为False ..不起作用。 – kaajaa328

+0

阅读[is-there-any-way-to-kill-a-thread-](https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-在python),[键盘中断多线程](https://stackoverflow.com/questions/43721150/python-keyboardinterrupt-in-multithreading),[键盘中断](https://stackoverflow.com/questions/4136632/ ctrl-cie-keyboardinterrupt-to-kill-threads-in-python) – stovfl

回答

1

以下工作。尽管Thread子类中的try...except从未被触发,但主线程能够捕获到KeyboardInterrupts。

MyThread子类的run()方法的代码是什么是CPython的2.7的来源为Thread.run()方法,它已经包含一个try/finally修改版本...,其余以打印消息加入except BaseException as exc:当发生任何类型的事件时。

import threading 
import time 

def method1(args): 
    print('method1() running') 
    while True: 
     time.sleep(.001) 

def method2(args): 
    print('method2() running') 
    while True: 
     time.sleep(.01) 


class MyThread(threading.Thread): 
    def __init__(self, *args, **kwargs): 
     super(MyThread, self).__init__(*args, **kwargs) 

    def run(self): 
     """ Method representing the thread's activity. 

     You may override this method in a subclass. The standard run() method 
     invokes the callable object passed to the object's constructor as the 
     target argument, if any, with sequential and keyword arguments taken 
     from the args and kwargs arguments, respectively. 
     """ 
     try: 
      print('in MyThread.run()\n') 
      if self._Thread__target: 
       self._Thread__target(*self._Thread__args, **self._Thread__kwargs) 
     except BaseException as exc: 
      print('reraising Exception {}'.format(exc)) 
      raise typeof(exc)(str(exc)) 
     finally: 
      # Avoid a refcycle if the thread is running a function with 
      # an argument that has a member that points to the thread. 
      del self._Thread__target, self._Thread__args, self._Thread__kwargs 
      print('exiting') 

args1 = 1 
t1 = MyThread(target=method1, args=(args1,)) 
t1.daemon = True 

args2 = 2 
t2 = MyThread(target=method2, args=(args2,)) 
t2.daemon = True 
t1.start() 
t2.start() 

try: 
    while True: 
     time.sleep(1) 
except BaseException as exc: 
    print('exception "{}" occurred'.format(type(exc))) 
    quit() 

控制台输出(I输入Ctrl-C键的method1() running出现后右):

> python not-catching-keyboardinterrupt.py 
in MyThread.run() 
in MyThread.run() 

method2() running 

method1() running 
exception "<type 'exceptions.KeyboardInterrupt'>" occurred