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

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

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

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

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

3 ответа

Решение

Я написал о перебрасывании исключений в 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

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

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

К сожалению, принятый ответ не отвечает на вопрос. Вы бы предпочли передать детали исключения в очередь. Пожалуйста, обратите внимание: поймать исключение потока в потоке вызывающего в Python

Другие вопросы по тегам