Assume the following scenario:
- Create a new pythread
- Call a C++ function from within that pythread
- That C++ function calls some Python
- That Python calls some MORE C++
Here is the minimum working example:
#include<pybind11/pybind11.h>
#include<pybind11/embed.h>
#include<iostream>
#include<thread>staticvoidthread()
{
pybind11::gil_scoped_acquire acquire;
{
// Pretend this block is nested inside Python
pybind11::gil_scoped_release release;
std::cout << "Calling C++ code" << std::endl;
}
}
staticvoidinit_threads()
{
// NOTE: This is a workaround for #1273if (!PyEval_ThreadsInitialized())
{
{
pybind11::gil_scoped_acquire acquire;
}
PyEval_SaveThread();
}
}
staticconstchar thread_code[] =
"import threading\n""import testmod\n""t = threading.Thread(target=testmod.func)\n""t.start()\n""t.join()\n";
PYBIND11_EMBEDDED_MODULE(testmod, m)
{
m.def("func", thread, pybind11::call_guard<pybind11::gil_scoped_release>());
}
intmain()
{
pybind11::scoped_interpreter interp;
init_threads();
{
pybind11::gil_scoped_acquire acquire;
pybind11::exec(thread_code);
}
return0;
}When the inner nested gil_scoped_release is destructed, it causes the Python interpreter to throw a fatal error:
Calling C++ code
Fatal Python error: Invalid thread state for this thread
Aborted (core dumped)
because there are two different thread states for the same thread, one created by the pythread and one created by pybind.
Assume the following scenario:
Here is the minimum working example:
When the inner nested
gil_scoped_releaseis destructed, it causes the Python interpreter to throw a fatal error:because there are two different thread states for the same thread, one created by the pythread and one created by pybind.