문제

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.

도움이 되었습니까?

해결책

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).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top