Py_DECREF(o);
}
+ The function is not thread-safe in the :term:`free-threaded <free threading>`
+ build without external synchronization. You can use
+ :c:macro:`Py_BEGIN_CRITICAL_SECTION` to lock the dictionary while iterating
+ over it::
+
+ Py_BEGIN_CRITICAL_SECTION(self->dict);
+ while (PyDict_Next(self->dict, &pos, &key, &value)) {
+ ...
+ }
+ Py_END_CRITICAL_SECTION();
+
.. c:function:: int PyDict_Merge(PyObject *a, PyObject *b, int override)
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
===================
+-----------------------------------+-----------------------------------+
| :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` |
+-----------------------------------+-----------------------------------+
--- /dev/null
+:c:func:`PyDict_Next` no longer locks the dictionary in the free-threaded
+build. The locking needs to be done by the caller around the entire iteration
+loop.
if (!PyDict_Check(op))
return 0;
- ASSERT_DICT_LOCKED(op);
-
mp = (PyDictObject *)op;
i = *ppos;
if (_PyDict_HasSplitTable(mp)) {
int
PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
{
- int res;
- Py_BEGIN_CRITICAL_SECTION(op);
- res = _PyDict_Next(op, ppos, pkey, pvalue, NULL);
- Py_END_CRITICAL_SECTION();
- return res;
+ return _PyDict_Next(op, ppos, pkey, pvalue, NULL);
}