@@ -227,6 +227,61 @@ For example::
227227 If the interpreter finalized before ``PyThreadState_Swap `` was called, then
228228 ``interp `` will be a dangling pointer!
229229
230+ Reusing a thread state across repeated calls
231+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
232+
233+ Creating and destroying a :c:type: `PyThreadState ` is not free, and is
234+ more expensive on a :term: `free-threaded build `. If a non-Python thread
235+ calls into the interpreter many times, creating a fresh thread state on
236+ every entry and destroying it on every exit is a performance
237+ anti-pattern. Instead, create the thread state once (when the native
238+ thread starts, or lazily on its first call into Python), attach and
239+ detach it around each call, and destroy it when the native thread
240+ exits::
241+
242+ /* Thread startup: create the state once. */
243+ PyThreadState *tstate = PyThreadState_New(interp);
244+
245+ /* Per-call: attach, run Python, detach. */
246+ PyEval_RestoreThread(tstate);
247+ result = CallSomeFunction();
248+ PyEval_SaveThread();
249+
250+ /* ... many more calls ... */
251+
252+ /* Thread shutdown: destroy the state once. */
253+ PyEval_RestoreThread(tstate);
254+ PyThreadState_Clear(tstate);
255+ PyThreadState_DeleteCurrent();
256+
257+ The equivalent with the :ref: `PyGILState API <gilstate >` keeps an *outer *
258+ :c:func: `PyGILState_Ensure ` outstanding for the thread's lifetime, so
259+ nested Ensure/Release pairs never drop the internal nesting counter to
260+ zero::
261+
262+ /* Thread startup: create and pin the state. */
263+ PyGILState_STATE outer = PyGILState_Ensure();
264+ PyThreadState *saved = PyEval_SaveThread();
265+
266+ /* Per-call: the thread state already exists. */
267+ PyGILState_STATE inner = PyGILState_Ensure();
268+ result = CallSomeFunction();
269+ PyGILState_Release(inner);
270+
271+ /* ... many more calls ... */
272+
273+ /* Thread shutdown: unpin and destroy the state. */
274+ PyEval_RestoreThread(saved);
275+ PyGILState_Release(outer);
276+
277+ The embedding code must arrange for the shutdown sequence to run before
278+ the native thread exits, and before :c:func: `Py_FinalizeEx ` is called.
279+ If interpreter finalization begins first, the shutdown
280+ :c:func: `PyEval_RestoreThread ` call will hang the thread (see
281+ :c:func: `PyEval_RestoreThread ` for details) rather than return. If the
282+ native thread exits without running the shutdown sequence, the thread
283+ state is leaked for the remainder of the process.
284+
230285.. _gilstate :
231286
232287Legacy API
0 commit comments