-
|
Hi Everyone I am trying to get a simple prototype where objects are created in the main thread, each of them owning a sub-interpreter. These objects will be used from different threads calling some embed python script, but the object keeps the subinterpreter alive until it goes out of scope, but I am not understanding the subinterpreters or when are some objects destroyed. probably once the Main interpreter is gone, and it is crashing on me. The next sample does work and is based pybind11 example about subinterpreters. #include <iostream>
#include <pybind11/embed.h>
#include <pybind11/gil.h>
#include <pybind11/subinterpreter.h>
namespace py = pybind11;
PYBIND11_EMBEDDED_MODULE(printer, m, py::multiple_interpreters::per_interpreter_gil()) {
m.def("which", [](const std::string& when) {
std::cout << when << "; Current Interpreter is "
<< py::subinterpreter::current().id()
<< std::endl;
});
}
// forgive me for this, I don't want to the main interpreter unless someone needs it.
// Here it will be created only if required, and it will outlive main, and be destroyed afterwards
bool CreateMainInterpreter()
{
py::scoped_interpreter *MainInterpreter = new py::scoped_interpreter;
return true;
}
int main() {
bool Initialize{ CreateMainInterpreter() };
try {
// in the main thread, and the main interpreter
py::module_::import("printer").attr("which")("First init");
{ // <--- I would want a different thread for this block.
py::subinterpreter sub = py::subinterpreter::create(); //(1) create, but the gil goes back to the main interpreter
py::subinterpreter_scoped_activate guard(sub); //(2) activate this subinterpreter
py::module_::import("printer").attr("which")("Created sub"); //(3) call code from subinterpreter, the gil is captured
}; // (4)
} catch (py::error_already_set &e) {
std::cerr << "EXCEPTION " << e.what() << std::endl;
return 1;
}
return 0;
}I am assuming that at (4) gil is released (back to main/previous interpreter) The output is the expected one... Now, if I wrap the task in a thread, the code will segmentation fault. { // wrap previous code in a thread
std::thread Task{ []() {
// (5) nothing preventing the task from starting like it was doing before
py::subinterpreter sub = py::subinterpreter::create(); //(1) create, but the gil goes back to the main interpreter
py::subinterpreter_scoped_activate guard(sub); //(2) activate this subinterpreter
py::module_::import("printer").attr("which")("Created sub"); //(3) call code from subinterpreter, the gil is captured
});
// (6) Nothing required for the Task to release the subprocess gil, etc and die, et all.
Task.join();
} sadlly I get... Any ideas on what assumptions I got wrong? Thanks |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
|
I worked it out. int main() {
bool Initialize{ CreateMainInterpreter() };
try
{
py::module_::import("printer").attr("which")("First init");
//py::gil_scoped_release release; // <-- this would do the trick, but anywhere before the join should work.
std::thread Task( []() {
py::gil_scoped_acquire scope;
py::subinterpreter sub = py::subinterpreter::create();
py::subinterpreter_scoped_activate guard(sub);
py::module_::import("printer").attr("which")("Created sub");
} );
py::gil_scoped_release release;
Task.join();
}
catch (py::error_already_set &e)
{
std::cerr << "EXCEPTION " << e.what() << std::endl;
throw std::runtime_error( e.what() );
}
return 0;
} |
Beta Was this translation helpful? Give feedback.
I worked it out.
It seems the main process/thread needs to let the GIL go.