Reputation: 529
I'm trying to use SWIG directors to call Python code from C++. However if the code is running in another thread, I must acquire the GIL. My code looks roughly like this (minus the thread stuff):
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>
How can I acquire the GIL before calling the Python callback?
To elaborate, the threads
feature of SWIG creates code that releases the GIL when C++ code is called, but when Python code is called from C++ it isn't reacquired, so that's what I want to do.
The call stack looks like this: Python -> Foo.doSomething
-> C++ -> Callback.call
-> Python.
Upvotes: 2
Views: 973
Reputation: 29621
Acquiring the GUIL is explained clearly in Non-Python created threads subsection of Thread State and the Global Interpreter Lock section in Python manual. But you say the issue is how to do this from SWIG generated code. How about this, added to your SWIG .i file:
struct PythonCallback: public Callback
{
virtual void call() {
getGIL();
lockedCall();
releaseGIL();
}
virtual void lockedCall() {} // will be overwritten in Python
};
You only need to expose PythonCallback
(not Callback) and its lockedCall
method, which you can rename to call
if you wish via SWIG's %rename
directive. Then in Python you would derive from PythonCallback
, and override the call
method (which in reality is the lockedCall
method if you %rename
'd it).
Upvotes: 2