Skip to content

Commit 9d7365d

Browse files
committed
Clarify the PyGILState variant in the docs...
as being an init, do things, finalizer trio where lots of stuff without the GIL held can happen inbetween. There might not be a GIL but when used in builds where there is you don't want to hold it. There's an internal recursion counter within the PyGILState APIs, if it goes to 0 on Release, any Python thread state that it created is destroyed. We're working around that. Should I mention that internals detail?
1 parent 24c05e2 commit 9d7365d

File tree

1 file changed

+14
-6
lines changed

1 file changed

+14
-6
lines changed

Doc/c-api/threads.rst

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,20 +257,28 @@ exits::
257257
The equivalent with the :ref:`PyGILState API <gilstate>` keeps an *outer*
258258
:c:func:`PyGILState_Ensure` outstanding for the thread's lifetime, so
259259
nested Ensure/Release pairs never drop the internal nesting counter to
260-
zero::
260+
zero.
261+
262+
In thread startup, pin the state and immediately detach so the thread
263+
does not hold the GIL while off doing non-Python work. Stash ``outer``
264+
and ``saved`` somewhere that survives for the thread's lifetime (for
265+
example, in thread-local storage)::
261266

262-
/* Thread startup: create and pin the state. */
263267
PyGILState_STATE outer = PyGILState_Ensure();
264-
PyThreadState *saved = PyEval_SaveThread();
268+
PyThreadState *saved = PyEval_SaveThread();
269+
270+
Each subsequent call into Python from this thread reuses the pinned
271+
state; the inner Release decrements the nesting counter but does not
272+
destroy the thread state because the outer Ensure is still
273+
outstanding::
265274

266-
/* Per-call: the thread state already exists. */
267275
PyGILState_STATE inner = PyGILState_Ensure();
268276
result = CallSomeFunction();
269277
PyGILState_Release(inner);
270278

271-
/* ... many more calls ... */
279+
At thread shutdown, re-attach and drop the outer reference to destroy
280+
the thread state::
272281

273-
/* Thread shutdown: unpin and destroy the state. */
274282
PyEval_RestoreThread(saved);
275283
PyGILState_Release(outer);
276284

0 commit comments

Comments
 (0)