I'm trying to understand sub-interpreters and GIL. But my experiment is failing often(The same code rarely works).
Gathering info from SO questions and few sites, I have the following code which spawns 2 non-python threads. Each of these threads are given a python sub-interpreter. I want to release GIL inside these threads and call a DLL function in C++(though this example does not detail that. Here I just write to stdout). Basically I want to see concurrency in the execution(Non-Python DLL invocation).
#include <iostream>
#include <thread>
#include <Python.h>
void worker(PyInterpreterState* interp, int n)
{
PyThreadState* ts;
ts = PyThreadState_New(interp);
PyThreadState_Swap(ts);
PyThreadState* _save;
_save = PyEval_SaveThread();
std::cout << n << std::endl; // Non-Python execution. My Focus.
PyEval_RestoreThread(_save);
PyThreadState_Swap(ts);
PyThreadState_Clear(ts);
PyThreadState_DeleteCurrent();
return;
}
int main()
{
try
{
Py_Initialize();
PyEval_InitThreads();
PyThreadState* _main = PyThreadState_Get();
PyThreadState* i1 = Py_NewInterpreter();
PyThreadState* i2 = Py_NewInterpreter();
std::thread t1(worker, i1->interp, 1);
std::thread t2(worker, i2->interp, 2);
t1.join();
t2.join();
PyThreadState_Swap(i1);
PyThreadState_Clear(i1);
Py_EndInterpreter(i1);
PyThreadState_Swap(i2);
PyThreadState_Clear(i2);
Py_EndInterpreter(i2);
PyThreadState_Swap(_main);
Py_Finalize();
return 0;
}
catch(std::exception& e)
{
std::cout << "Exception:" << std::endl << e.what() << std::endl;
}
}
Running a single thread works all the time. When I run 2 threads as shown, I get any of the following outputs.
- In
PyEval_SaveThread()
,
2
Fatal Python error: drop_gil: GIL is not locked
Python runtime state: initialized
Current thread 0x00002d08 (most recent call first):
<no Python frame>
- In
PyEval_SaveThread()
,
1
Fatal Python error: PyEval_SaveThread: NULL tstate
Python runtime state: initialized
Current thread 0x00003eb8 (most recent call first):
<no Python frame>
Either of the thread succeeds, the other one fails.
- Rarely works. The same code.
1
2
Can someone shed some light on this? Need help. Thanks.
PyInterpreterState*
withts->interp
and you're getting it by mis-casting thePyThreadState*
– Puggreets->interp
didn't help. Same issues. You are right, my question is based on the post you pointed, but that does not solve my problem. – RefutationPyThreadState*
to aPyInterpreterState*
is definitely 100% wrong. I suggest you edit your post to fix that, and then hopefully someone else knows the answer to the rest of it. – Puggree