ANSWERED
好的,我解决了这个问题。它是如何初始化线程状态的。您根本不需要使用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&lt;&gt;调用该方法。 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在我的代码中的其他地方被调用no,no else应该调用python。
更新
我已经阅读了另一个问题,该问题建议模块中的导入线程作为运行
的替代方法PyEval_InitThreads();
PyEval_ReleaseLock();
但是,当我在模块之前导入线程并从boost python包装中删除上面两行时,它似乎不起作用。
答案 0 :(得分:9)
好的,我解决了这个问题。它是如何初始化线程状态的。您根本不需要使用ReleaseLock。只需将InitThreads调用添加到模块定义中:
BOOST_PYTHON_MODULE(ModuleName)
{
PyEval_InitThreads();
...
}