Skip to content

Commit 594e298

Browse files
committed
Further split up threads.rst.
1 parent 38539b9 commit 594e298

4 files changed

Lines changed: 463 additions & 461 deletions

File tree

Doc/c-api/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ document the API functions in detail.
2323
concrete.rst
2424
interp-lifecycle.rst
2525
threads.rst
26+
synchronization.rst
27+
tls.rst
2628
subinterpreters.rst
2729
profiling.rst
2830
init_config.rst

Doc/c-api/synchronization.rst

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
.. highlight:: c
2+
3+
Synchronization Primitives
4+
==========================
5+
6+
The C-API provides a basic mutual exclusion lock.
7+
8+
.. c:type:: PyMutex
9+
10+
A mutual exclusion lock. The :c:type:`!PyMutex` should be initialized to
11+
zero to represent the unlocked state. For example::
12+
13+
PyMutex mutex = {0};
14+
15+
Instances of :c:type:`!PyMutex` should not be copied or moved. Both the
16+
contents and address of a :c:type:`!PyMutex` are meaningful, and it must
17+
remain at a fixed, writable location in memory.
18+
19+
.. note::
20+
21+
A :c:type:`!PyMutex` currently occupies one byte, but the size should be
22+
considered unstable. The size may change in future Python releases
23+
without a deprecation period.
24+
25+
.. versionadded:: 3.13
26+
27+
.. c:function:: void PyMutex_Lock(PyMutex *m)
28+
29+
Lock mutex *m*. If another thread has already locked it, the calling
30+
thread will block until the mutex is unlocked. While blocked, the thread
31+
will temporarily detach the :term:`thread state <attached thread state>` if one exists.
32+
33+
.. versionadded:: 3.13
34+
35+
.. c:function:: void PyMutex_Unlock(PyMutex *m)
36+
37+
Unlock mutex *m*. The mutex must be locked --- otherwise, the function will
38+
issue a fatal error.
39+
40+
.. versionadded:: 3.13
41+
42+
.. c:function:: int PyMutex_IsLocked(PyMutex *m)
43+
44+
Returns non-zero if the mutex *m* is currently locked, zero otherwise.
45+
46+
.. note::
47+
48+
This function is intended for use in assertions and debugging only and
49+
should not be used to make concurrency control decisions, as the lock
50+
state may change immediately after the check.
51+
52+
.. versionadded:: 3.14
53+
54+
.. _python-critical-section-api:
55+
56+
Python Critical Section API
57+
---------------------------
58+
59+
The critical section API provides a deadlock avoidance layer on top of
60+
per-object locks for :term:`free-threaded <free threading>` CPython. They are
61+
intended to replace reliance on the :term:`global interpreter lock`, and are
62+
no-ops in versions of Python with the global interpreter lock.
63+
64+
Critical sections are intended to be used for custom types implemented
65+
in C-API extensions. They should generally not be used with built-in types like
66+
:class:`list` and :class:`dict` because their public C-APIs
67+
already use critical sections internally, with the notable
68+
exception of :c:func:`PyDict_Next`, which requires critical section
69+
to be acquired externally.
70+
71+
Critical sections avoid deadlocks by implicitly suspending active critical
72+
sections, hence, they do not provide exclusive access such as provided by
73+
traditional locks like :c:type:`PyMutex`. When a critical section is started,
74+
the per-object lock for the object is acquired. If the code executed inside the
75+
critical section calls C-API functions then it can suspend the critical section thereby
76+
releasing the per-object lock, so other threads can acquire the per-object lock
77+
for the same object.
78+
79+
Variants that accept :c:type:`PyMutex` pointers rather than Python objects are also
80+
available. Use these variants to start a critical section in a situation where
81+
there is no :c:type:`PyObject` -- for example, when working with a C type that
82+
does not extend or wrap :c:type:`PyObject` but still needs to call into the C
83+
API in a manner that might lead to deadlocks.
84+
85+
The functions and structs used by the macros are exposed for cases
86+
where C macros are not available. They should only be used as in the
87+
given macro expansions. Note that the sizes and contents of the structures may
88+
change in future Python versions.
89+
90+
.. note::
91+
92+
Operations that need to lock two objects at once must use
93+
:c:macro:`Py_BEGIN_CRITICAL_SECTION2`. You *cannot* use nested critical
94+
sections to lock more than one object at once, because the inner critical
95+
section may suspend the outer critical sections. This API does not provide
96+
a way to lock more than two objects at once.
97+
98+
Example usage::
99+
100+
static PyObject *
101+
set_field(MyObject *self, PyObject *value)
102+
{
103+
Py_BEGIN_CRITICAL_SECTION(self);
104+
Py_SETREF(self->field, Py_XNewRef(value));
105+
Py_END_CRITICAL_SECTION();
106+
Py_RETURN_NONE;
107+
}
108+
109+
In the above example, :c:macro:`Py_SETREF` calls :c:macro:`Py_DECREF`, which
110+
can call arbitrary code through an object's deallocation function. The critical
111+
section API avoids potential deadlocks due to reentrancy and lock ordering
112+
by allowing the runtime to temporarily suspend the critical section if the
113+
code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`.
114+
115+
.. c:macro:: Py_BEGIN_CRITICAL_SECTION(op)
116+
117+
Acquires the per-object lock for the object *op* and begins a
118+
critical section.
119+
120+
In the free-threaded build, this macro expands to::
121+
122+
{
123+
PyCriticalSection _py_cs;
124+
PyCriticalSection_Begin(&_py_cs, (PyObject*)(op))
125+
126+
In the default build, this macro expands to ``{``.
127+
128+
.. versionadded:: 3.13
129+
130+
.. c:macro:: Py_BEGIN_CRITICAL_SECTION_MUTEX(m)
131+
132+
Locks the mutex *m* and begins a critical section.
133+
134+
In the free-threaded build, this macro expands to::
135+
136+
{
137+
PyCriticalSection _py_cs;
138+
PyCriticalSection_BeginMutex(&_py_cs, m)
139+
140+
Note that unlike :c:macro:`Py_BEGIN_CRITICAL_SECTION`, there is no cast for
141+
the argument of the macro - it must be a :c:type:`PyMutex` pointer.
142+
143+
On the default build, this macro expands to ``{``.
144+
145+
.. versionadded:: 3.14
146+
147+
.. c:macro:: Py_END_CRITICAL_SECTION()
148+
149+
Ends the critical section and releases the per-object lock.
150+
151+
In the free-threaded build, this macro expands to::
152+
153+
PyCriticalSection_End(&_py_cs);
154+
}
155+
156+
In the default build, this macro expands to ``}``.
157+
158+
.. versionadded:: 3.13
159+
160+
.. c:macro:: Py_BEGIN_CRITICAL_SECTION2(a, b)
161+
162+
Acquires the per-objects locks for the objects *a* and *b* and begins a
163+
critical section. The locks are acquired in a consistent order (lowest
164+
address first) to avoid lock ordering deadlocks.
165+
166+
In the free-threaded build, this macro expands to::
167+
168+
{
169+
PyCriticalSection2 _py_cs2;
170+
PyCriticalSection2_Begin(&_py_cs2, (PyObject*)(a), (PyObject*)(b))
171+
172+
In the default build, this macro expands to ``{``.
173+
174+
.. versionadded:: 3.13
175+
176+
.. c:macro:: Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2)
177+
178+
Locks the mutexes *m1* and *m2* and begins a critical section.
179+
180+
In the free-threaded build, this macro expands to::
181+
182+
{
183+
PyCriticalSection2 _py_cs2;
184+
PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)
185+
186+
Note that unlike :c:macro:`Py_BEGIN_CRITICAL_SECTION2`, there is no cast for
187+
the arguments of the macro - they must be :c:type:`PyMutex` pointers.
188+
189+
On the default build, this macro expands to ``{``.
190+
191+
.. versionadded:: 3.14
192+
193+
.. c:macro:: Py_END_CRITICAL_SECTION2()
194+
195+
Ends the critical section and releases the per-object locks.
196+
197+
In the free-threaded build, this macro expands to::
198+
199+
PyCriticalSection2_End(&_py_cs2);
200+
}
201+
202+
In the default build, this macro expands to ``}``.
203+
204+
.. versionadded:: 3.13
205+
206+
207+
Legacy Locking APIs
208+
-------------------
209+
210+
These APIs are obsolete since Python 3.13 with the introduction of
211+
:c:type:`PyMutex`.
212+
213+
.. versionchanged:: 3.15
214+
These APIs are now a simple wrapper around ``PyMutex``.
215+
216+
217+
.. c:type:: PyThread_type_lock
218+
219+
A pointer to a mutual exclusion lock.
220+
221+
222+
.. c:type:: PyLockStatus
223+
224+
The result of acquiring a lock with a timeout.
225+
226+
.. c:namespace:: NULL
227+
228+
.. c:enumerator:: PY_LOCK_FAILURE
229+
230+
Failed to acquire the lock.
231+
232+
.. c:enumerator:: PY_LOCK_ACQUIRED
233+
234+
The lock was successfully acquired.
235+
236+
.. c:enumerator:: PY_LOCK_INTR
237+
238+
The lock was interrupted by a signal.
239+
240+
241+
.. c:function:: PyThread_type_lock PyThread_allocate_lock(void)
242+
243+
Allocate a new lock.
244+
245+
On success, this function returns a lock; on failure, this
246+
function returns ``0`` without an exception set.
247+
248+
The caller does not need to hold an :term:`attached thread state`.
249+
250+
.. versionchanged:: 3.15
251+
This function now always uses :c:type:`PyMutex`. In prior versions, this
252+
would use a lock provided by the operating system.
253+
254+
255+
.. c:function:: void PyThread_free_lock(PyThread_type_lock lock)
256+
257+
Destroy *lock*. The lock should not be held by any thread when calling
258+
this.
259+
260+
The caller does not need to hold an :term:`attached thread state`.
261+
262+
263+
.. c:function:: PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, long long microseconds, int intr_flag)
264+
265+
Acquire *lock* with a timeout.
266+
267+
This will wait for *microseconds* microseconds to acquire the lock. If the
268+
timeout expires, this function returns :c:enumerator:`PY_LOCK_FAILURE`.
269+
If *microseconds* is ``-1``, this will wait indefinitely until the lock has
270+
been released.
271+
272+
If *intr_flag* is ``1``, acquiring the lock may be interrupted by a signal,
273+
in which case this function returns :c:enumerator:`PY_LOCK_INTR`. Upon
274+
interruption, it's generally expected that the caller makes a call to
275+
:c:func:`Py_MakePendingCalls` to propagate an exception to Python code.
276+
277+
If the lock is successfully acquired, this function returns
278+
:c:enumerator:`PY_LOCK_ACQUIRED`.
279+
280+
The caller does not need to hold an :term:`attached thread state`.
281+
282+
283+
.. c:function:: int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
284+
285+
Acquire *lock*.
286+
287+
If *waitflag* is ``1`` and another thread currently holds the lock, this
288+
function will wait until the lock can be acquired and will always return
289+
``1``.
290+
291+
If *waitflag* is ``0`` and another thread holds the lock, this function will
292+
not wait and instead return ``0``. If the lock is not held by any other
293+
thread, then this function will acquire it and return ``1``.
294+
295+
Unlike :c:func:`PyThread_acquire_lock_timed`, acquiring the lock cannot be
296+
interrupted by a signal.
297+
298+
The caller does not need to hold an :term:`attached thread state`.
299+
300+
301+
.. c:function:: int PyThread_release_lock(PyThread_type_lock lock)
302+
303+
Release *lock*. If *lock* is not held, then this function issues a
304+
fatal error.
305+
306+
The caller does not need to hold an :term:`attached thread state`.

0 commit comments

Comments
 (0)