Поднять необработанные исключения в потоке в основном потоке?
Есть несколько похожих вопросов, но ни один из них не отвечает за меня.
Если я создаю потоки через threading.Thread
, которые затем генерируют исключения, которые не обрабатываются, эти потоки завершаются. Я хочу сохранить распечатку по умолчанию из деталей исключения с помощью трассировки стека, но также уничтожить весь процесс.
Я посчитал, что можно было бы уловить все исключения в потоках и сделать ререйз на основном объекте потока, или, возможно, можно вручную выполнить обработку исключений по умолчанию, а затем поднять SystemExit
на основной поток.
Какой лучший способ сделать это?
Ответы
Ответ 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, весь процесс завершается, когда основной поток завершается).
Ответ 3
Очень, к сожалению, принятый ответ не отвечает на вопрос. Скорее всего, вы будете перенаправлять данные о исключениях в очередь. Пожалуйста, посмотрите: Поймать исключение потока в потоке вызывающего в Python