Как правильно завершить поток Python3 во время чтения потока

Я использую поток для чтения строк из потока (/ dev / tty1) при обработке других вещей в основном цикле. Я хочу, чтобы поток заканчивался вместе с основной программой при нажатии CTRL-C.

   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 () - здесь не работает. Какой рекомендуемый способ справиться с этим?

Я могу просто установить флаг Daemon, но тогда я не смогу использовать метод quit (), который может оказаться полезным позже (для некоторой очистки). Любые идеи?


person abw    schedule 05.05.2011    source источник


Ответы (2)


AFAIK, в Python 3 нет встроенного механизма для этого (как и в Python 2). Вы пробовали проверенный подход Python 2 с PyThreadState_SetAsyncExc, задокументированный здесь и здесь или альтернативный подход к трассировке здесь?

Вот немного измененная версия подхода 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(ctypes.c_long(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)
person Irfy    schedule 15.06.2011
comment
Я считаю, что мне нужно использовать ctypes.c_long(tid), иначе я получаю res == 0 - person faulty; 15.10.2014
comment
Я обновил код, чтобы использовать ctypes.c_long(tid) вместо просто tid, теперь он работает так, как задумано. Полностью рабочий текст. Фактически, асинхронное исключение может не прерывать блокирующее чтение из файлового объекта, таким образом становясь эквивалентным проверенному вручную флагу, который может быть установлен из основного потока, что является более чистым решением. Если требуется прерывание блокирующего чтения, можно использовать неблокирующий ввод-вывод. - person Irfy; 09.04.2018

Сделайте свой поток потоком демона. Когда все потоки, не являющиеся демонами, завершились, программа завершится. Поэтому, когда Ctrl-C передается вашей программе и основной поток завершается, нет необходимости явно убивать читателя.

    myReader = Reader()
    myReader.daemon = True
    myReader.start()
person weaver    schedule 12.09.2011