2009-12-06 1 views
12

Есть несколько похожих вопросов, но ни один из них не дает ответа, который мне нужен.Поднять необработанные исключения в потоке в основной теме?

Если я создаю потоки через threading.Thread, которые затем выдают исключение, которые не обрабатываются, эти потоки завершаются. Я хочу сохранить распечатку по умолчанию из деталей исключения с помощью трассировки стека, но также уничтожить весь процесс.

Я считал, что можно было бы поймать все исключения в потоках и ререйзировать их по основному потоку, или, возможно, можно вручную выполнить обработку исключений по умолчанию, а затем поднять SystemExit на основной нить.

Каков наилучший способ сделать это?

ответ

15

Я написал около Re-throwing exceptions in Python, включая что-то очень похожее на это в качестве примера.

На вашем рабочем потоке вы делаете это (Python 2.x см ниже Python 3.x версии):

try: 
    self.result = self.do_something_dangerous() 
except Exception, e: 
    import sys 
    self.exc_info = sys.exc_info() 

и на основном потоке вы делаете это:

if self.exc_info: 
    raise self.exc_info[1], None, self.exc_info[2] 
return self.result 

Исключение будет отображаться в основном потоке так же, как если бы он был поднят в рабочем потоке.

Python 3.x:

try: 
    self.result = self.do_something_dangerous() 
except Exception as e: 
    import sys 
    self.exc_info = sys.exc_info() 

и на главной теме:

if self.exc_info: 
    raise self.exc_info[1].with_traceback(self.exc_info[2]) 
return self.result 
+0

Не хотите ли вы бросить 'thrdobj.exc_info' в основном потоке и почему отказаться от типа исключения при повторном переводе? –

+0

Теперь я вижу, должен был прочитать заявление о повышении 3arg. но вопрос о 'self' все еще стоит, спасибо за хороший ответ, я попробую его –

+0

Я не уверен, что ваш вопрос о себе. Этот код исходил от объекта, который используется для отсрочки работы рабочего потока, поэтому один и тот же объект запускает код в рабочем и основном потоках. –

9

Единственное исключение вторичный поток может надежно поднять в основной нити KeyboardInterrupt: способ, вторичной нитью является вызов функции thread.interrupt_main(). Невозможно связать дополнительную информацию (о причине исключения) с созданным объектом исключения - последнее всегда просто равное KeyboardInterrupt. Таким образом, вам нужно спрятать эту информацию в другом месте, например. по специальному экземпляру Queue.Queue - эта информация может включать в себя результаты, которые вторичная нить может получить через sys.exc_info(), и все остальное, что вы найдете полезным, конечно.

Главный поток должен будет восстановить эту дополнительную информацию (и принять во внимание, что очередь будет пустой, если прерывание клавиатуры происходит из-за того, что пользователь нажимает на управление-C или тому подобное, поэтому используйте get_nowait и будьте готовы например, для обработки исключения Queue.Empty), отформатируйте его, как вы пожелаете, и завершите (если все вторичные потоки равны daemon с, весь процесс завершается, когда основной поток завершается).

+0

обновленная ссылка на документацию по потокам: https://docs.python.org/3.6/library/_thread.html?highlight=interrupt_main#_thread.interrupt_main – user2682863