ANSWERED为什么PyGILState_Release抛出致命的Python错误
好吧,我解决了这个问题。它的一切就是如何初始化线程状态。你根本不需要使用ReleaseLock。只需添加InitThreads打电话给你的模块定义:
BOOST_PYTHON_MODULE(ModuleName)
{
PyEval_InitThreads();
...
}
好吧,我试图弄清这个问题了几个小时,并通过什么似乎像在网络上每一个例子倒。现在变得疲惫,所以我可能会错过一些明显的东西,但这里是发生了什么:
我正在包装一个库在boost python。我正在运行一个python脚本,它导入lib,构造一些对象,然后从C++接收回调函数,这些回调函数会调用python。在我调用任何python函数之前,我试图获取全局解释器锁。以下是一些示例代码:
class ScopedGILRelease
{
public:
inline ScopedGILRelease()
{
d_gstate = PyGILState_Ensure();
}
inline ~ScopedGILRelease()
{
PyGILState_Release(d_gstate);
}
private:
PyGILState_STATE d_gstate;
};
class PyTarget : public DingoClient::ClientRequest::Target, public wrapper<DingoClient::ClientRequest::Target>
{
public:
PyTarget(PyObject* self_) : self(self_) {}
~PyTarget() {
ScopedGILRelease gil_lock;
}
PyObject* self;
void onData(const boost::shared_ptr<Datum>::P & data, const void * closure)
{
ScopedGILRelease gil_lock;
// invoke call_method to python
}
...
}
目标对象上的onData方法被库调用为回调函数。在python中,我们从PyTarget继承并实现另一种方法。然后我们使用call_method <>来调用该方法。 gil_lock获取锁并通过RIAA保证获取的线程状态始终是一个版本,并且在超出范围时实际上总是释放。
但是,当我在一个试图获得大量此函数的回调的脚本中运行它时,它总是出现段错误。脚本看起来是这样的:
# Initialize the library and setup callbacks
...
# Wait until user breaks
while 1:
pass
而且,Python脚本始终构成它运行的对象:
PyEval_InitThreads();
PyEval_ReleaseLock();
收到任何回调之前。
我已经减少了代码,我甚至没有在onData中调用python,我只是获取锁。在释放它总是崩溃,或者:
Fatal Python error: ceval: tstate mix-up
Fatal Python error: This thread state must be current when releasing
或
Fatal Python error: ceval: orphan tstate
Fatal Python error: This thread state must be current when releasing
这是看似随意。我在这里疯了吗,因为我觉得我正确使用GIL锁,但它似乎根本不起作用。
其他注意事项: 只有一个线程曾经调用Target对象的onData方法。
当我使用time.sleep()调用python模块的while循环时,它似乎允许脚本运行更长时间,但最终脚本会出现类似问题的段错误。它的持续时间与time.sleep(即time.sleep(10)的运行时间长于time.sleep(0.01))的时间成正比。这让我想到了脚本如何在未经我许可的情况下重新获取GIL 。
PyGILState_Release和PyGILState_Ensure在我的代码中没有其他地方被调用,没有其他地方应该调用到python中。
更新
我读过另一个问题这表明进口线程模块作为替代在运行
PyEval_InitThreads();
PyEval_ReleaseLock();
但是,它不会出现,当我导入之前线程工作我模块并从我的boost python包装器中删除上述两行。
很高兴您知道了。那个人也把我带回来了,回来的时候。仅供参考,您可以发布自己的问题的答案。这将让喜欢你的解决方案的人可以投票。 –
谢谢,相对较新的堆栈溢出,并仍然得到它的挂钩。将张贴。 –