Bug report
Bug description:
# Download https://gist.github.com/kevin85421/4616545d3bed2ebcfe5d0a01bdfde3ff
g++ example.cc -I/usr/include/python3.12 -lpython3.12 -lpthread -o example
./example
- The above script creates two C++ threads,
default_pool and custom_pool, and calls Python code.
- Phase 1 (
void init_python_thread): Each thread
- Calls
PyGILState_Ensure()
- Runs Python code that assigns the value 1 to the variable
a and creates a thread-local state using threading.local().
- Calls
PyEval_SaveThread to release GIL.
- Phase 2 (
void release_gstate): Each thread
- Calls
PyEval_RestoreThread(*tstate) to acquire GIL and restore thread state.
- Runs Python code to print
a
- Runs Python code to print thread-local state.
- Calls
PyGILState_Release
The thread who is the first thread to call PyGILState_Ensure() will fail to print thread-local state in step 2.
In the following example log,
default_pool calls PyGILState_Ensure() and writes a=1 and thread-local state.
custom_pool calls PyGILState_Ensure() and writes a=1 and thread-local state. => My current guess is that PyGILState_Ensure() here makes the thread-local state of default_pool be GCed.
[C++][08:21:37.740] Hello from the default_pool in init_python_thread
[C++][08:21:37.741] Hello from the custom_pool in init_python_thread
Hello from default_pool, a = 1!
[C++][08:21:37.744] Hello from the default_pool in release_gstate
Hello from custom_pool, a = 1!
a = 1 in release_gstate!
[C++][08:21:37.744] Hello from the custom_pool in release_gstate
Traceback (most recent call last):
File "<string>", line 1, in <module>
AttributeError: '_thread._local' object has no attribute 'name'
a = 1 in release_gstate!
thread_local.name = custom_pool in release_gstate!
CPython versions tested on:
3.12
Operating systems tested on:
Linux