有没有办法让 boost::python 控制与 python 的每次交互的 Python GIL?
我正在用 boost::python 编写一个项目。我正在尝试为外部库编写 C++ 包装器,并使用 python 脚本控制 C++ 库。我无法更改外部库,只能更改我的包装程序。(我正在为所述外部库编写功能测试应用程序)
外部库是用 C 语言编写的,并使用函数指针和回调来完成大量繁重的工作。它是一个消息传递系统,因此当消息进入时,会调用一个回调函数,例如。
我在我的库中实现了一种观察者模式,以便多个对象可以监听一个回调。我所有的主要玩家都正确导出,并且在一定程度上我可以很好地控制事情。
外部库创建线程来处理消息、发送消息、处理等。其中一些回调可能会从不同的进程中调用,我最近发现 python 不是线程安全的。
这些观察者可以在 python 中定义,所以我需要能够调用 python 并且 python 需要在任何时候调用我的程序。
我像这样设置对象和观察者
class TestObserver( MyLib.ConnectionObserver ):
def receivedMsg( self, msg ):
print("Received a message!")
ob = TestObserver()
cnx = MyLib.Conection()
cnx.attachObserver( ob )
然后我创建一个发送到连接的源并调用 receivedMsg 函数。
所以一个常规的 source.send('msg') 将进入我的 C++ 应用程序,进入 C 库,它将发送消息,连接将获取它,然后调用回调,它返回到我的 C++ 库和connection 试图通知所有的观察者,此时就是这里的python类,所以它调用了那个方法。
当然回调是从连接线程调用的,而不是主应用程序线程。
昨天一切都崩溃了,我无法发送 1 条消息。然后在 Cplusplus-sig 档案中四处挖掘之后,我了解了 GIL 和几个漂亮的功能来锁定东西。
所以我的观察者类的 C++ python 包装器现在看起来像这样
struct IConnectionObserver_wrapper : Observers::IConnectionObserver, wrapper<Observers::IConnectionObserver>
{
void receivedMsg( const Message* msg )
{
PyGILState_STATE gstate = PyGILState_Ensure();
if( override receivedMsg_func = this->get_override( "receivedMsg" ) )
receivedMsg_func( msg );
Observers::IConnectionObserver::receivedMsg( msg );
PyGILState_Release( gstate );
}
}
但是,当我尝试发送超过 250 条这样的消息时,这很有效
for i in range(250)
source.send('msg")
它再次崩溃。具有与以前相同的信息和症状,
PyThreadState_Get: no current thread
所以我想这次我在调用我的 C++ 应用程序时遇到问题,而不是调用 python。
我的问题是,有没有办法让 boost::python 为每次与 python 的交互处理 GIL 本身?我在代码中找不到任何东西,而且很难找到 source.send 调用进入 boost_python 的位置:(