Подтвердить что ты не робот

Поднять необработанные исключения в потоке в основном потоке?

Есть несколько похожих вопросов, но ни один из них не отвечает за меня.

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

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

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

4b9b3361

Ответ 1

Я писал о Re-throwing exceptions в 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

Ответ 2

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

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