“ PyThreadState_SetAsyncExc”导致“ SystemError:Exception Exception()不是BaseException子类”

时间:2019-03-28 11:55:08

标签: python multithreading exception python-c-api

我正在编写带有线程和挂钩的Python扩展模块。我需要将异常从我的一个线程抛出到Python主线程。为此,我使用int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)。在文档中说:

  

exc是要引发的异常对象

没有什么比这容易的了。但是,当我使用PyThreadState_SetAsyncExc(实际上是Exception)实例作为PyExc_Exception来调用exc时,我得到了

  

SystemError: exception Exception('Error text') not a BaseException subclass

我可以阅读:),所以我尝试放置的不是类实例(如我在文档中所述),而是直接将类对象作为exc放置,并且工作起来很麻烦。但是,结果是,我无法将参数传递给它。

此代码在主线程中导致系统错误:

PyGILState_STATE gstate = PyGILState_Ensure();
PyThreadState_SetAsyncExc(self->main_thread_id, PyObject_CallObject(PyExc_Exception, Py_BuildValue("(s)", "Error text")));
PyGILState_Release(gstate);

此代码在主线程中导致预期的Exception

PyGILState_STATE gstate = PyGILState_Ensure();
PyThreadState_SetAsyncExc(self->main_thread_id, PyExc_Exception);
PyGILState_Release(gstate);

完整的错误文本,IDLE显示:

Traceback (most recent call last):
** IDLE Internal Exception: 
  File "C:\Python37-32\lib\idlelib\run.py", line 137, in main
    request = rpc.request_queue.get(block=True, timeout=0.05)
  File "C:\Python37-32\lib\queue.py", line 179, in get
    self.not_empty.wait(remaining)
  File "C:\Python37-32\lib\threading.py", line 300, in wait
    gotit = waiter.acquire(True, timeout)
SystemError: exception Exception('Error text') not a BaseException subclass

因此,我希望PyThreadState_SetAsyncExc支持异常实例对象,但看起来它仅支持类/类型对象。 我对么?还是我做错了?

1 个答案:

答案 0 :(得分:0)

是的,您是正确的。您需要指定例外类型,而不是实例。文档可能对此更加清楚。

如果要提供带有异常的自定义错误消息,则可以使用PyErr_NewException函数来创建自己的异常类型:

PyGILState_STATE gstate = PyGILState_Ensure();
PyObject* exc = PyErr_NewException("mymodule.MyError: error message", NULL, NULL);
PyThreadState_SetAsyncExc(self->main_thread_id, exc);
Py_DECREF(exc);
PyGILState_Release(gstate);