Skip to content

Commit 2f2b70d

Browse files
authored
Simplify threading and API guidelines in documentation
Removed sections on API guidelines, critical sections, and thread safety from the documentation.
1 parent b8b5277 commit 2f2b70d

1 file changed

Lines changed: 17 additions & 238 deletions

File tree

Doc/howto/freethreading-stable-abi.rst

Lines changed: 17 additions & 238 deletions
Original file line numberDiff line numberDiff line change
@@ -98,259 +98,37 @@ for :ref:`single-phase initialization <single-phase-initialization>`
9898
(that is, :c:func:`PyModule_Create`), they are not exposed when targeting the regular Stable ABI.
9999
Prefer multi-phased initializtion when possible.
100100

101-
General API Guidelines
102-
======================
103101

104-
Most of the C API is thread-safe, but there are some exceptions.
105-
106-
* **Struct Fields**: Accessing fields in Python C API objects or structs
107-
directly is not thread-safe if the field may be concurrently modified.
108-
* **Borrowed References**: C API functions that return
109-
:term:`borrowed references <borrowed reference>` may not be thread-safe if
110-
the containing object is modified concurrently. See the section on
111-
:ref:`borrowed references <borrowed-references>` for more information.
112-
113-
114-
Container Thread Safety
115-
.......................
116-
117-
Containers like :c:struct:`PyListObject`,
118-
:c:struct:`PyDictObject`, and :c:struct:`PySetObject` perform internal locking
119-
in the free-threaded build. For example, the :c:func:`PyList_Append` will
120-
lock the list before appending an item.
121-
122-
Borrowed References
123-
===================
124-
125-
.. _borrowed-references:
102+
Critical Sections
103+
=================
126104

127-
Some C API functions return :term:`borrowed references <borrowed reference>`.
128-
These APIs are not thread-safe if the containing object is modified
129-
concurrently. For example, it's not safe to use :c:func:`PyList_GetItem`
130-
if the list may be modified concurrently.
105+
.. _critical-sections:
131106

132-
The following table lists some borrowed reference APIs and their replacements
133-
that return :term:`strong references <strong reference>`.
107+
Replacements:
134108

135109
+-----------------------------------+-----------------------------------+
136-
| Borrowed reference API | Strong reference API |
110+
| Macro functions | C API functions |
137111
+===================================+===================================+
138-
| :c:func:`PyList_GetItem` | :c:func:`PyList_GetItemRef` |
112+
| :c:func:`Py_BEGIN_CRITICAL_SECTION` | :c:func:`PyCriticalSection_Begin` |
113+
| :c:func:`Py_END_CRITICAL_SECTION` | |:c:func:`PyCriticalSection_End` |
139114
+-----------------------------------+-----------------------------------+
140-
| :c:func:`PyList_GET_ITEM` | :c:func:`PyList_GetItemRef` |
115+
| :c:func:`Py_BEGIN_CRITICAL_SECTION2` | :c:func:`PyCriticalSection2_Begin` |
116+
| :c:func:`Py_END_CRITICAL_SECTION2` | |:c:func:`PyCriticalSection2_End` |
141117
+-----------------------------------+-----------------------------------+
142-
| :c:func:`PyDict_GetItem` | :c:func:`PyDict_GetItemRef` |
118+
| :c:func:`Py_BEGIN_CRITICAL_SECTION_MUTEX` | :c:func:`PyCriticalSection_BeginMutex` |
119+
| :c:func:`Py_END_CRITICAL_SECTION` | |:c:func:`PyCriticalSection_End` |
143120
+-----------------------------------+-----------------------------------+
144-
| :c:func:`PyDict_GetItemWithError` | :c:func:`PyDict_GetItemRef` |
121+
| :c:func:`Py_BEGIN_CRITICAL_SECTION2_MUTEX` | :c:func:`PyCriticalSection2_BeginMutex` |
122+
| :c:func:`Py_END_CRITICAL_SECTION2` | |:c:func:`PyCriticalSection2_End` |
145123
+-----------------------------------+-----------------------------------+
146-
| :c:func:`PyDict_GetItemString` | :c:func:`PyDict_GetItemStringRef` |
147-
+-----------------------------------+-----------------------------------+
148-
| :c:func:`PyDict_SetDefault` | :c:func:`PyDict_SetDefaultRef` |
149-
+-----------------------------------+-----------------------------------+
150-
| :c:func:`PyDict_Next` | none (see :ref:`PyDict_Next`) |
151-
+-----------------------------------+-----------------------------------+
152-
| :c:func:`!PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` |
153-
+-----------------------------------+-----------------------------------+
154-
| :c:func:`!PyWeakref_GET_OBJECT` | :c:func:`PyWeakref_GetRef` |
155-
+-----------------------------------+-----------------------------------+
156-
| :c:func:`PyImport_AddModule` | :c:func:`PyImport_AddModuleRef` |
157-
+-----------------------------------+-----------------------------------+
158-
| :c:func:`PyCell_GET` | :c:func:`PyCell_Get` |
159-
+-----------------------------------+-----------------------------------+
160-
161-
Not all APIs that return borrowed references are problematic. For
162-
example, :c:func:`PyTuple_GetItem` is safe because tuples are immutable.
163-
Similarly, not all uses of the above APIs are problematic. For example,
164-
:c:func:`PyDict_GetItem` is often used for parsing keyword argument
165-
dictionaries in function calls; those keyword argument dictionaries are
166-
effectively private (not accessible by other threads), so using borrowed
167-
references in that context is safe.
168-
169-
Some of these functions were added in Python 3.13. You can use the
170-
`pythoncapi-compat <https://github.com/python/pythoncapi-compat>`_ package
171-
to provide implementations of these functions for older Python versions.
172-
173-
174-
Thread State and GIL APIs
175-
=========================
176-
177-
Python provides a set of functions and macros to manage thread state and the
178-
GIL, such as:
179-
180-
* :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release`
181-
* :c:func:`PyEval_SaveThread` and :c:func:`PyEval_RestoreThread`
182-
* :c:macro:`Py_BEGIN_ALLOW_THREADS` and :c:macro:`Py_END_ALLOW_THREADS`
183-
184-
These functions should still be used in the free-threaded build to manage
185-
thread state even when the :term:`GIL` is disabled. For example, if you
186-
create a thread outside of Python, you must call :c:func:`PyGILState_Ensure`
187-
before calling into the Python API to ensure that the thread has a valid
188-
Python thread state.
189-
190-
You should continue to call :c:func:`PyEval_SaveThread` or
191-
:c:macro:`Py_BEGIN_ALLOW_THREADS` around blocking operations, such as I/O or
192-
lock acquisitions, to allow other threads to run the
193-
:term:`cyclic garbage collector <garbage collection>`.
194-
195-
196-
Protecting Internal Extension State
197-
===================================
198-
199-
Your extension may have internal state that was previously protected by the
200-
GIL. You may need to add locking to protect this state. The approach will
201-
depend on your extension, but some common patterns include:
202-
203-
* **Caches**: global caches are a common source of shared state. Consider
204-
using a lock to protect the cache or disabling it in the free-threaded build
205-
if the cache is not critical for performance.
206-
* **Global State**: global state may need to be protected by a lock or moved
207-
to thread local storage. C11 and C++11 provide the ``thread_local`` or
208-
``_Thread_local`` for
209-
`thread-local storage <https://en.cppreference.com/w/c/language/storage_duration>`_.
210-
211-
212-
Critical Sections
213-
=================
214-
215-
.. _critical-sections:
216-
217-
In the free-threaded build, CPython provides a mechanism called "critical
218-
sections" to protect data that would otherwise be protected by the GIL.
219-
While extension authors may not interact with the internal critical section
220-
implementation directly, understanding their behavior is crucial when using
221-
certain C API functions or managing shared state in the free-threaded build.
222-
223-
What Are Critical Sections?
224-
...........................
225-
226-
Conceptually, critical sections act as a deadlock avoidance layer built on
227-
top of simple mutexes. Each thread maintains a stack of active critical
228-
sections. When a thread needs to acquire a lock associated with a critical
229-
section (e.g., implicitly when calling a thread-safe C API function like
230-
:c:func:`PyDict_SetItem`, or explicitly using macros), it attempts to acquire
231-
the underlying mutex.
232-
233-
Using Critical Sections
234-
.......................
235-
236-
The primary APIs for using critical sections are:
237-
238-
* :c:macro:`Py_BEGIN_CRITICAL_SECTION` and :c:macro:`Py_END_CRITICAL_SECTION` -
239-
For locking a single object
240-
241-
* :c:macro:`Py_BEGIN_CRITICAL_SECTION2` and :c:macro:`Py_END_CRITICAL_SECTION2`
242-
- For locking two objects simultaneously
243-
244-
These macros must be used in matching pairs and must appear in the same C
245-
scope, since they establish a new local scope. These macros are no-ops in
246-
non-free-threaded builds, so they can be safely added to code that needs to
247-
support both build types.
248-
249-
A common use of a critical section would be to lock an object while accessing
250-
an internal attribute of it. For example, if an extension type has an internal
251-
count field, you could use a critical section while reading or writing that
252-
field::
253-
254-
// read the count, returns new reference to internal count value
255-
PyObject *result;
256-
Py_BEGIN_CRITICAL_SECTION(obj);
257-
result = Py_NewRef(obj->count);
258-
Py_END_CRITICAL_SECTION();
259-
return result;
260-
261-
// write the count, consumes reference from new_count
262-
Py_BEGIN_CRITICAL_SECTION(obj);
263-
obj->count = new_count;
264-
Py_END_CRITICAL_SECTION();
265-
266-
267-
How Critical Sections Work
268-
..........................
269-
270-
Unlike traditional locks, critical sections do not guarantee exclusive access
271-
throughout their entire duration. If a thread would block while holding a
272-
critical section (e.g., by acquiring another lock or performing I/O), the
273-
critical section is temporarily suspended—all locks are released—and then
274-
resumed when the blocking operation completes.
275-
276-
This behavior is similar to what happens with the GIL when a thread makes a
277-
blocking call. The key differences are:
278-
279-
* Critical sections operate on a per-object basis rather than globally
280-
281-
* Critical sections follow a stack discipline within each thread (the "begin" and
282-
"end" macros enforce this since they must be paired and within the same scope)
283-
284-
* Critical sections automatically release and reacquire locks around potential
285-
blocking operations
286-
287-
Deadlock Avoidance
288-
..................
289-
290-
Critical sections help avoid deadlocks in two ways:
291-
292-
1. If a thread tries to acquire a lock that's already held by another thread,
293-
it first suspends all of its active critical sections, temporarily releasing
294-
their locks
295-
296-
2. When the blocking operation completes, only the top-most critical section is
297-
reacquired first
298-
299-
This means you cannot rely on nested critical sections to lock multiple objects
300-
at once, as the inner critical section may suspend the outer ones. Instead, use
301-
:c:macro:`Py_BEGIN_CRITICAL_SECTION2` to lock two objects simultaneously.
302-
303-
Note that the locks described above are only :c:type:`PyMutex` based locks.
304-
The critical section implementation does not know about or affect other locking
305-
mechanisms that might be in use, like POSIX mutexes. Also note that while
306-
blocking on any :c:type:`PyMutex` causes the critical sections to be
307-
suspended, only the mutexes that are part of the critical sections are
308-
released. If :c:type:`PyMutex` is used without a critical section, it will
309-
not be released and therefore does not get the same deadlock avoidance.
310-
311-
Important Considerations
312-
........................
313-
314-
* Critical sections may temporarily release their locks, allowing other threads
315-
to modify the protected data. Be careful about making assumptions about the
316-
state of the data after operations that might block.
317-
318-
* Because locks can be temporarily released (suspended), entering a critical
319-
section does not guarantee exclusive access to the protected resource
320-
throughout the section's duration. If code within a critical section calls
321-
another function that blocks (e.g., acquires another lock, performs blocking
322-
I/O), all locks held by the thread via critical sections will be released.
323-
This is similar to how the GIL can be released during blocking calls.
324-
325-
* Only the lock(s) associated with the most recently entered (top-most)
326-
critical section are guaranteed to be held at any given time. Locks for
327-
outer, nested critical sections might have been suspended.
328-
329-
* You can lock at most two objects simultaneously with these APIs. If you need
330-
to lock more objects, you'll need to restructure your code.
331-
332-
* While critical sections will not deadlock if you attempt to lock the same
333-
object twice, they are less efficient than purpose-built reentrant locks for
334-
this use case.
335-
336-
* When using :c:macro:`Py_BEGIN_CRITICAL_SECTION2`, the order of the objects
337-
doesn't affect correctness (the implementation handles deadlock avoidance),
338-
but it's good practice to always lock objects in a consistent order.
339-
340-
* Remember that the critical section macros are primarily for protecting access
341-
to *Python objects* that might be involved in internal CPython operations
342-
susceptible to the deadlock scenarios described above. For protecting purely
343-
internal extension state, standard mutexes or other synchronization
344-
primitives might be more appropriate.
345124

346125
Platform-specific considerations
347126
................................
348127

349128
On some platforms, Python will look for and load shared library files named
350-
with the ``abi3`` or ``abi3t`` tag (for example, ``mymodule.abi3.so``).
351-
:term:`Free-threaded <free-threaded build>` interpreters only recognize the
352-
``abi3t`` tag, while non-free-threaded ones will prefer ``abi3`` but fall back
353-
to ``abi3t``.
129+
with the ``abi3`` or ``abi3t`` tag (for example, ``mymodule.abi3t.so``).
130+
:term:`Free-threaded <free-threaded build>` interpreters prefer ``abi3t``,
131+
but can fall back to ``abi3``.
354132
Thus, extensions compatible with both ABIs should use the ``abi3t`` tag.
355133

356134
Python does not necessarily check that extensions it loads
@@ -365,6 +143,7 @@ If you use
365143
`setuptools <https://setuptools.pypa.io/en/latest/setuptools.html>`_ to build
366144
your extension, a future version of ``setuptools`` will allow ``py_limited_api=True``
367145
to be set to allow targeting limited API when building with the free-threaded build.
146+
``uv`` supports targeting PEP 803 as of 0.11.3: `https://github.com/astral-sh/uv/releases/tag/0.11.3`.
368147

369148
`Other build tools will support this ABI as well <https://packaging.python.org/en/latest/guides/tool-recommendations/#build-backends-for-extension-modules>`_.
370149

0 commit comments

Comments
 (0)