为什么PyGILState_Release引发致命的Python错误 [英] Why is PyGILState_Release throwing Fatal Python Errors

查看:442
本文介绍了为什么PyGILState_Release引发致命的Python错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

回答

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

Ok, I solved this issue. Its all in how you initialize the thread state. You don't need to use ReleaseLock at all. Simply add InitThreads call to your module definition:

BOOST_PYTHON_MODULE(ModuleName)
{
    PyEval_InitThreads();

    ...
}


好吧,我已经尝试诊断这个问题了好几个小时,并倾听了网络上每个示例的内容.现在累了,所以我可能会遗漏一些明显的东西,但这是正在发生的事情:


Ok, I have attempted to diagnose this problem for hours and poured through what seems like every example on the web. Getting tired now so I may be missing something obvious but here is what is happening:

我正在用boost python包装一个库.我正在运行一个python脚本,该脚本导入lib,构造一些对象,然后接收来自c ++的回调,这些回调调用python.在调用任何python函数之前,我尝试获取全局解释器锁.这是一些示例代码:

I am wrapping a library in boost python. I am running a python script which imports the lib, constructs some objects and then receives callbacks from c++ which calls back into python. Before I invoke call any python functions, I attempt to acquire the global interpreter lock. Here is some sample code:

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保证获取的线程状态始终是一个发行版,并且实际上在超出范围时总是被释放.

The onData method on the Target object is called by the library as a callback. In python, we inherit from PyTarget and implement another method. We then use call_method<> to call that method. gil_lock acquires the lock and through RIAA guarantees that the thread state acquired is always the one release and that it is in fact always released when going out of scope.

但是,当我在试图获取此函数大量回调的脚本中运行此脚本时,它始终会出现段错误.脚本看起来像这样:

However when I run this in a script which attempts to get a large number of callbacks on this function, it always segfaults. Script looks something like this:

# Initialize the library and setup callbacks
...

# Wait until user breaks
while 1:
  pass

此外,python脚本总是构造一个运行对象:

Also, the python script always constructs an object which runs:

PyEval_InitThreads();
PyEval_ReleaseLock();

在接收任何回调之前.

我已经将代码简化为我甚至没有在onData中调用python的地方,我只是获得了锁.发行后,它总是崩溃,其中之一:

I've reduced the code to where I'm not even calling into python in onData, I'm just acquiring the lock. On release it always crashes with either:

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锁,但是它似乎根本不起作用.

It is seemingly random. Am I crazy here, because I feel like I'm using the GIL lock correctly, however it doesn't seem to work at all.

其他说明: 只有一个线程调用过该Target对象的onData方法.

Other Notes: Only one thread ever calls that Target object's onData method.

当我使用time.sleep()在调用python模块的while循环中睡眠时,似乎允许脚本运行更长的时间,但最终脚本会出现类似问题的段错误.它持续的时间与time.sleep(即time.sleep(10)运行的时间长于time.sleep(0.01))成正比.这让我想到了一些未经我允许而脚本如何重新获取GIL的情况

When I sleep in the while loop in the calling python module with time.sleep(), it seems to allow the script to run longer but eventually script will segfault with similar problems. The amount of time it lasts is proportional to the amount of time.sleep (i.e. time.sleep(10) runs longer than time.sleep(0.01). This makes me think some how the script is re-acquiring the GIL without my permission.

在我的代码中没有其他地方调用PyGILState_Release和PyGILState_Ensure,没有其他地方应该调用python.

PyGILState_Release and PyGILState_Ensure is called no where else in my code, no where else should be calling into python.

更新

我读了另一个问题,建议在模块中使用导入线程代替运行

I've read another question which suggests import threading in the module as an alternative to running

PyEval_InitThreads();
PyEval_ReleaseLock();

但是,当我在模块之前导入线程并从boost python包装器中删除以上两行时,它似乎不起作用.

However, it does not appear to work when I import threading before my module and remove the above two lines from my boost python wrapper.

推荐答案

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

Ok, I solved this issue. Its all in how you initialize the thread state. You don't need to use ReleaseLock at all. Simply add InitThreads call to your module definition:

BOOST_PYTHON_MODULE(ModuleName)
{
    PyEval_InitThreads();

    ...
}

这篇关于为什么PyGILState_Release引发致命的Python错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆