Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python interpreter as a c++ class

I am working on embedding python in to c++. In some peculiar case I require two separate instances of the interpreter in same thread.

Can I wrap Python interpreter in to a c++ class and get services from two or more class instances?

like image 695
Amol Gawai Avatar asked Sep 26 '09 05:09

Amol Gawai


2 Answers

mosaik's answer did not work in my situation where my module is a plugin to a host application that already initializes python. I was able to get it to work with the following code.

// initialize interpreter
::PyEval_InitThreads();
::PyThreadState *mainThread = ::PyThreadState_Get();
myState = ::Py_NewInterpreter();
... // call python code
::PyThreadState_Swap(mainThread);

... // any other code

mainThread = ::PyThreadState_Swap(myState)
... // call python code
::PyThreadState_Swap(mainThread)

... // any other code

// finished with interpreter
mainThread = ::PyThreadState_Swap(myState)
::Py_EndInterpreter(myState);
::PyThreadState_Swap(mainThread)

When I called PyEval_AcquireLock() the program blocked and the function did not return. Further, calling PyEval_ReleaseThread(myState) seemed to invalidate the interpreter also.

like image 189
Jason Avatar answered Oct 01 '22 22:10

Jason


I have used Py_NewInterpreter for different interpreters in different threads, but this should also work for several interpreters within one thread:

In the main thread:

Py_Initialize();
PyEval_InitThreads();
mainThreadState = PyEval_SaveThread();

For each interpreter instance (in any thread):

// initialize interpreter
PyEval_AcquireLock();                // get the GIL
myThreadState = Py_NewInterpreter();
... // call python code
PyEval_ReleaseThread(myThreadState); // swap out thread state + release the GIL

... // any other code

// continue with interpreter
PyEval_AcquireThread(myThreadState); // get GIL + swap in thread state
... // call python code
PyEval_ReleaseThread(myThreadState);

... // any other code

// finish with interpreter
PyEval_AcquireThread(myThreadState);
... // call python code
Py_EndInterpreter(myThreadState);
PyEval_ReleaseLock();                // release the GIL

Note that you need a variable myThreadState for each interpreter instance!

Finally the finish in the main thread:

PyEval_RestoreThread(mainThreadState);
Py_Finalize();

There are some restrictions with using several interpreter instances (they seem not to be totally independent), but in most cases this does not seem to cause problems.

like image 44
mosaik Avatar answered Oct 01 '22 23:10

mosaik