diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2024-06-24 18:41:19 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-24 18:41:19 (GMT) |
commit | 0a77058b7971ba140c1f9db443e536ea5f1d71aa (patch) | |
tree | b49acc756824d61cbf0ff353ceab54311b24fe2a /Doc/howto/free-threading-extensions.rst | |
parent | 6aee5edb84cfa23f430091270a4118e51894c767 (diff) | |
download | cpython-0a77058b7971ba140c1f9db443e536ea5f1d71aa.zip cpython-0a77058b7971ba140c1f9db443e536ea5f1d71aa.tar.gz cpython-0a77058b7971ba140c1f9db443e536ea5f1d71aa.tar.bz2 |
[3.13] gh-120858: PyDict_Next should not lock the dict (GH-120859) (#120964)
PyDict_Next no longer locks the dictionary in the free-threaded build. Locking
around individual PyDict_Next calls is not sufficient because the function
returns borrowed references and because it allows concurrent modifications
during the iteraiton loop.
The internal locking also interferes with correct external synchronization
because it may suspend outer critical sections created by the caller.
(cherry picked from commit 375b723d5873f948696c7e85a97f4778d9e00ff0)
Co-authored-by: Sam Gross <colesbury@gmail.com>
Diffstat (limited to 'Doc/howto/free-threading-extensions.rst')
-rw-r--r-- | Doc/howto/free-threading-extensions.rst | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/Doc/howto/free-threading-extensions.rst b/Doc/howto/free-threading-extensions.rst index 080170d..1ba91b0 100644 --- a/Doc/howto/free-threading-extensions.rst +++ b/Doc/howto/free-threading-extensions.rst @@ -114,6 +114,24 @@ Containers like :c:struct:`PyListObject`, in the free-threaded build. For example, the :c:func:`PyList_Append` will lock the list before appending an item. +.. _PyDict_Next: + +``PyDict_Next`` +''''''''''''''' + +A notable exception is :c:func:`PyDict_Next`, which does not lock the +dictionary. You should use :c:macro:`Py_BEGIN_CRITICAL_SECTION` to protect +the dictionary while iterating over it if the dictionary may be concurrently +modified:: + + Py_BEGIN_CRITICAL_SECTION(dict); + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(dict, &pos, &key, &value)) { + ... + } + Py_END_CRITICAL_SECTION(); + Borrowed References =================== @@ -141,7 +159,7 @@ that return :term:`strong references <strong reference>`. +-----------------------------------+-----------------------------------+ | :c:func:`PyDict_SetDefault` | :c:func:`PyDict_SetDefaultRef` | +-----------------------------------+-----------------------------------+ -| :c:func:`PyDict_Next` | no direct replacement | +| :c:func:`PyDict_Next` | none (see :ref:`PyDict_Next`) | +-----------------------------------+-----------------------------------+ | :c:func:`PyWeakref_GetObject` | :c:func:`PyWeakref_GetRef` | +-----------------------------------+-----------------------------------+ |