SWIG:如何用自定义代码包装C++方法调用?
我正在尝试使用SWIG的directors功能,从C++调用Python代码。不过,如果代码在另一个线程中运行,我必须获取全局解释器锁(GIL)。我的代码大致是这样的(不包括线程的部分):
struct Callback {
virtual ~Callback() {}
virtual void call() {} // will be overwritten in Python
};
struct Foo {
Callback *c;
Foo(Callback* c) : c(c) {}
void doSomething() { c->call(); } // being called from another thread
};
Python:
from demo import *
class MyCallback(Callback):
def call(*args):
print("python callback")
c = MyCallback()
f = Foo(c)
f.doSomething()
Swig:
%module(directors="1", threads="1") demo
%feature("director");
%{
#include <test.h>
%}
%thread;
%include <test.h>
我该如何在调用Python回调之前获取GIL呢?
具体来说,SWIG的threads
功能会生成一些代码,在调用C++代码时会释放GIL,但当从C++调用Python代码时,它并不会重新获取GIL,所以我想要实现这个功能。
调用的顺序是这样的:Python -> Foo.doSomething
-> C++ -> Callback.call
-> Python。
1 个回答
2
获取GUIL(全局解释器锁)的过程在Python手册的线程状态和全局解释器锁部分的非Python创建的线程小节中讲得很清楚。不过你提到的问题是如何在SWIG生成的代码中做到这一点。可以这样做,添加到你的SWIG .i文件中:
struct PythonCallback: public Callback
{
virtual void call() {
getGIL();
lockedCall();
releaseGIL();
}
virtual void lockedCall() {} // will be overwritten in Python
};
你只需要暴露PythonCallback
(而不是Callback)和它的lockedCall
方法。如果你愿意,可以通过SWIG的%rename
指令把它改名为call
。然后在Python中,你可以从PythonCallback
继承,并重写call
方法(实际上如果你用%rename
改名的话,这个方法就是lockedCall
)。