2011-05-05 1236 views
4

我正在使用線程在處理主循環中的其他內容時從流(/ dev/tty1)讀取字符串。我希望線程在按CTRL-C時與主程序一起終止。如何在讀取流時正確終止Python3線程

from threading import Thread 

    class myReader(Thread): 
     def run(self): 
     with open('/dev/tty1', encoding='ascii') as myStream: 
      for myString in myStream: 
       print(myString) 
     def quit(self): 
     pass # stop reading, close stream, terminate the thread 

    myReader = Reader() 
    myReader.start() 
    while(True): 
     try: 
     pass # do lots of stuff 
     KeyboardInterrupt: 
     myReader.quit() 
     raise 

通常的解決方案 - run()循環內的布爾變量 - 在這裏不起作用。建議如何處理這個問題?

我可以只設置守護程序標誌,但後來我將無法使用quit()方法,這在以後可能證明有價值(做一些清理)。有任何想法嗎?

回答

4

AFAIK,在Python 3中沒有內置機制(就像在Python 2中一樣)。您是否嘗試過使用經過驗證的Python 2方法PyThreadState_SetAsyncExc,記錄爲herehere,或者替代追蹤方法here

下面是PyThreadState_SetAsyncExc方法的一個稍作修改的版本從上面:

 
import threading 
import inspect 
import ctypes 

def _async_raise(tid, exctype): 
    """raises the exception, performs cleanup if needed""" 
    if not inspect.isclass(exctype): 
     exctype = type(exctype) 
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) 
    if res == 0: 
     raise ValueError("invalid thread id") 
    elif res != 1: 
     # """if it returns a number greater than one, you're in trouble, 
     # and you should call it again with exc=NULL to revert the effect""" 
     ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) 
     raise SystemError("PyThreadState_SetAsyncExc failed") 

def stop_thread(thread): 
    _async_raise(thread.ident, SystemExit) 
+0

我發現我需要'ctypes.c_long(tid)',否則我會得到'res == 0' – faulty 2014-10-15 03:22:40

4

讓你的線程daemon thread。當所有非守護線程退出時,程序退出。所以,當Ctrl-C傳遞給你的程序並且主線程退出時,不需要明確地終止閱讀器。

myReader = Reader() 
    myReader.daemon = True 
    myReader.start()