Open
Description
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>
static void thread()
{
pybind11::gil_scoped_acquire acquire;
{
// Pretend this block is nested inside Python
pybind11::gil_scoped_release release;
std::cout << "Calling C++ code" << std::endl;
}
}
static void init_threads()
{
// NOTE: This is a workaround for #1273
if (!PyEval_ThreadsInitialized())
{
{
pybind11::gil_scoped_acquire acquire;
}
PyEval_SaveThread();
}
}
static const char 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>());
}
int main()
{
pybind11::scoped_interpreter interp;
init_threads();
{
pybind11::gil_scoped_acquire acquire;
pybind11::exec(thread_code);
}
return 0;
}
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.
Metadata
Metadata
Assignees
Labels
No labels