-
Notifications
You must be signed in to change notification settings - Fork 1
Make critical section API public as part of non-limited C API #26
Description
The critical section API provides macros for locking one or two Python objects at a time. I propose making the following macros public as part of Include/cpython (i.e., the non-limited C API):
Py_BEGIN_CRITICAL_SECTION(PyObject *op)/Py_END_CRITICAL_SECTION()Py_BEGIN_CRITICAL_SECTION2(PyObject *a, PyObject *b)/Py_END_CRITICAL_SECTION2()
These macros are defined, but no-ops, in the default build.
PR draft: python/cpython#119353
Public header: Include/cpython/critical_section.h
PEP 703 section: https://peps.python.org/pep-0703/#python-critical-sections
Note that the PR draft doesn't currently have user facing documentation. I'll add that, but I'm hoping to get a decision on the proposed API first.
Why is this useful?
C API extensions may need to add synchronization to be thread-safe without the GIL. In some cases, straightforward per-object locking can introduce deadlocks that were not present when running with the GIL. This API avoids that by implicitly suspending critical sections in places where the GIL would be released.
This makes it easier to add locking to extensions without introducing deadlocks.In the "nogil" fork, we used this to make https://github.com/gaogaotiantian/viztracer thread-safe, and we've also used this extensively within CPython.
Note that in some cases plain mutexes are still more appropriate: the Py_BEGIN/END_CRITICAL_SECTION API makes it easier to avoid deadlocks, but plain mutexes make it easier to reason about the invariant that the mutex ensures.
Why is this part of CPython?
The underlying implementation hooks in to the PyThreadState management, so it would not be possible to implement this outside of CPython.