【问题标题】:Why is PyGILState_Release throwing Fatal Python Errors为什么 PyGILState_Release 会抛出致命的 Python 错误
【发布时间】:2012-01-17 02:10:11
【问题描述】:

已回答

好的,我解决了这个问题。一切都在于您如何初始化线程状态。您根本不需要使用 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 
    }

    ...
}

Target 对象上的 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 包装器中删除上述两行时,它似乎不起作用。

【问题讨论】:

  • 很高兴你知道了。那个也让我回来了。仅供参考,您可以发布自己问题的答案。这会让喜欢你的解决方案的人投票。
  • 谢谢,相对较新的堆栈溢出,仍然掌握它的窍门。将发布。

标签: c++ python boost boost-python


【解决方案1】:

好的,我解决了这个问题。一切都在于您如何初始化线程状态。您根本不需要使用 ReleaseLock。只需将 InitThreads 调用添加到您的模块定义中:

BOOST_PYTHON_MODULE(ModuleName)
{
    PyEval_InitThreads();

    ...
}

【讨论】:

    猜你喜欢
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 2013-10-11
    • 2020-05-17
    • 2018-12-10
    相关资源
    最近更新 更多