Skip to content

Commit c6973ee

Browse files
authored
Add Doc section in free-threaded extension howto for critical sections (GH-132531)
1 parent f5512a2 commit c6973ee

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

Doc/howto/free-threading-extensions.rst

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,141 @@ depend on your extension, but some common patterns include:
243243
`thread-local storage <https://en.cppreference.com/w/c/language/storage_duration>`_.
244244

245245

246+
Critical Sections
247+
=================
248+
249+
.. _critical-sections:
250+
251+
In the free-threaded build, CPython provides a mechanism called "critical
252+
sections" to protect data that would otherwise be protected by the GIL.
253+
While extension authors may not interact with the internal critical section
254+
implementation directly, understanding their behavior is crucial when using
255+
certain C API functions or managing shared state in the free-threaded build.
256+
257+
What Are Critical Sections?
258+
...........................
259+
260+
Conceptually, critical sections act as a deadlock avoidance layer built on
261+
top of simple mutexes. Each thread maintains a stack of active critical
262+
sections. When a thread needs to acquire a lock associated with a critical
263+
section (e.g., implicitly when calling a thread-safe C API function like
264+
:c:func:`PyDict_SetItem`, or explicitly using macros), it attempts to acquire
265+
the underlying mutex.
266+
267+
Using Critical Sections
268+
.......................
269+
270+
The primary APIs for using critical sections are:
271+
272+
* :c:macro:`Py_BEGIN_CRITICAL_SECTION` and :c:macro:`Py_END_CRITICAL_SECTION` -
273+
For locking a single object
274+
275+
* :c:macro:`Py_BEGIN_CRITICAL_SECTION2` and :c:macro:`Py_END_CRITICAL_SECTION2`
276+
- For locking two objects simultaneously
277+
278+
These macros must be used in matching pairs and must appear in the same C
279+
scope, since they establish a new local scope. These macros are no-ops in
280+
non-free-threaded builds, so they can be safely added to code that needs to
281+
support both build types.
282+
283+
A common use of a critical section would be to lock an object while accessing
284+
an internal attribute of it. For example, if an extension type has an internal
285+
count field, you could use a critical section while reading or writing that
286+
field::
287+
288+
// read the count, returns new reference to internal count value
289+
PyObject *result;
290+
Py_BEGIN_CRITICAL_SECTION(obj);
291+
result = Py_NewRef(obj->count);
292+
Py_END_CRITICAL_SECTION();
293+
return result;
294+
295+
// write the count, consumes reference from new_count
296+
Py_BEGIN_CRITICAL_SECTION(obj);
297+
obj->count = new_count;
298+
Py_END_CRITICAL_SECTION();
299+
300+
301+
How Critical Sections Work
302+
..........................
303+
304+
Unlike traditional locks, critical sections do not guarantee exclusive access
305+
throughout their entire duration. If a thread would block while holding a
306+
critical section (e.g., by acquiring another lock or performing I/O), the
307+
critical section is temporarily suspended—all locks are released—and then
308+
resumed when the blocking operation completes.
309+
310+
This behavior is similar to what happens with the GIL when a thread makes a
311+
blocking call. The key differences are:
312+
313+
* Critical sections operate on a per-object basis rather than globally
314+
315+
* Critical sections follow a stack discipline within each thread (the "begin" and
316+
"end" macros enforce this since they must be paired and within the same scope)
317+
318+
* Critical sections automatically release and reacquire locks around potential
319+
blocking operations
320+
321+
Deadlock Avoidance
322+
..................
323+
324+
Critical sections help avoid deadlocks in two ways:
325+
326+
1. If a thread tries to acquire a lock that's already held by another thread,
327+
it first suspends all of its active critical sections, temporarily releasing
328+
their locks
329+
330+
2. When the blocking operation completes, only the top-most critical section is
331+
reacquired first
332+
333+
This means you cannot rely on nested critical sections to lock multiple objects
334+
at once, as the inner critical section may suspend the outer ones. Instead, use
335+
:c:macro:`Py_BEGIN_CRITICAL_SECTION2` to lock two objects simultaneously.
336+
337+
Note that the locks described above are only :c:type:`!PyMutex` based locks.
338+
The critical section implementation does not know about or affect other locking
339+
mechanisms that might be in use, like POSIX mutexes. Also note that while
340+
blocking on any :c:type:`!PyMutex` causes the critical sections to be
341+
suspended, only the mutexes that are part of the critical sections are
342+
released. If :c:type:`!PyMutex` is used without a critical section, it will
343+
not be released and therefore does not get the same deadlock avoidance.
344+
345+
Important Considerations
346+
........................
347+
348+
* Critical sections may temporarily release their locks, allowing other threads
349+
to modify the protected data. Be careful about making assumptions about the
350+
state of the data after operations that might block.
351+
352+
* Because locks can be temporarily released (suspended), entering a critical
353+
section does not guarantee exclusive access to the protected resource
354+
throughout the section's duration. If code within a critical section calls
355+
another function that blocks (e.g., acquires another lock, performs blocking
356+
I/O), all locks held by the thread via critical sections will be released.
357+
This is similar to how the GIL can be released during blocking calls.
358+
359+
* Only the lock(s) associated with the most recently entered (top-most)
360+
critical section are guaranteed to be held at any given time. Locks for
361+
outer, nested critical sections might have been suspended.
362+
363+
* You can lock at most two objects simultaneously with these APIs. If you need
364+
to lock more objects, you'll need to restructure your code.
365+
366+
* While critical sections will not deadlock if you attempt to lock the same
367+
object twice, they are less efficient than purpose-built reentrant locks for
368+
this use case.
369+
370+
* When using :c:macro:`Py_BEGIN_CRITICAL_SECTION2`, the order of the objects
371+
doesn't affect correctness (the implementation handles deadlock avoidance),
372+
but it's good practice to always lock objects in a consistent order.
373+
374+
* Remember that the critical section macros are primarily for protecting access
375+
to *Python objects* that might be involved in internal CPython operations
376+
susceptible to the deadlock scenarios described above. For protecting purely
377+
internal extension state, standard mutexes or other synchronization
378+
primitives might be more appropriate.
379+
380+
246381
Building Extensions for the Free-Threaded Build
247382
===============================================
248383

0 commit comments

Comments
 (0)