@@ -5209,6 +5209,112 @@ Note, the *elem* argument to the :meth:`~object.__contains__`,
52095209:meth: `~set.discard ` methods may be a set. To support searching for an equivalent
52105210frozenset, a temporary one is created from *elem *.
52115211
5212+ .. admonition :: Thread safety
5213+
5214+ The :func: `len ` function is lock-free and :term: `atomic <atomic operation> `.
5215+
5216+ The following read operation is lock-free. It does not block concurrent
5217+ modifications and may observe intermediate states from operations that
5218+ hold the per-object lock:
5219+
5220+ .. code-block ::
5221+ :class: good
5222+
5223+ elem in s # set.__contains__
5224+
5225+ This operation may compare elements using :meth: `~object.__eq__ `, which can
5226+ execute arbitrary Python code. During such comparisons, the set may be
5227+ modified by another thread. For built-in types like :class: `str `,
5228+ :class: `int `, and :class: `float `, :meth: `!__eq__ ` does not release the
5229+ underlying lock during comparisons and this is not a concern.
5230+
5231+ All other operations from here on hold the per-object lock.
5232+
5233+ Adding or removing a single element is safe to call from multiple threads
5234+ and will not corrupt the set:
5235+
5236+ .. code-block ::
5237+ :class: good
5238+
5239+ s.add(elem) # add element
5240+ s.remove(elem) # remove element, raise if missing
5241+ s.discard(elem) # remove element if present
5242+ s.pop() # remove and return arbitrary element
5243+
5244+ These operations also compare elements, so the same :meth: `~object.__eq__ `
5245+ considerations as above apply.
5246+
5247+ The following operations return new objects and hold the per-object lock
5248+ for the duration:
5249+
5250+ .. code-block ::
5251+ :class: good
5252+
5253+ s.copy() # returns a shallow copy
5254+
5255+ The :meth: `~set.clear ` method holds the lock for its duration. Other
5256+ threads cannot observe elements being removed.
5257+
5258+ The following operations only accept :class: `set ` or :class: `frozenset `
5259+ as operands and always lock both objects:
5260+
5261+ .. code-block ::
5262+ :class: good
5263+
5264+ s |= other # other must be set/frozenset
5265+ s &= other # other must be set/frozenset
5266+ s -= other # other must be set/frozenset
5267+ s ^= other # other must be set/frozenset
5268+ s & other # other must be set/frozenset
5269+ s | other # other must be set/frozenset
5270+ s - other # other must be set/frozenset
5271+ s ^ other # other must be set/frozenset
5272+
5273+ :meth: `set.update `, :meth: `set.union `, :meth: `set.intersection ` and
5274+ :meth: `set.difference ` can take multiple iterables as arguments. They all
5275+ iterate through all the passed iterables and do the following:
5276+
5277+ * :meth: `set.update ` and :meth: `set.union ` lock both objects only when
5278+ the other operand is a :class: `set `, :class: `frozenset `, or :class: `dict `.
5279+ * :meth: `set.intersection ` and :meth: `set.difference ` always try to lock
5280+ all objects.
5281+
5282+ :meth: `set.symmetric_difference ` tries to lock both objects.
5283+
5284+ The update variants of the above methods also have some differences between
5285+ them:
5286+
5287+ * :meth: `set.difference_update ` and :meth: `set.intersection_update ` try
5288+ to lock all objects.
5289+ * :meth: `set.symmetric_difference_update ` only lock the argument if it is
5290+ of type :class: `set `, :class: `frozenset `, or :class: `dict `.
5291+
5292+ The following methods always try to lock both objects:
5293+
5294+ .. code-block ::
5295+ :class: good
5296+
5297+ s.isdisjoint(other) # both locked
5298+ s.issubset(other) # both locked
5299+ s.issuperset(other) # both locked
5300+
5301+ Operations that involve multiple accesses, as well as iteration, are never
5302+ atomic:
5303+
5304+ .. code-block ::
5305+ :class: bad
5306+
5307+ # NOT atomic: check-then-act
5308+ if elem in s:
5309+ s.remove(elem)
5310+
5311+ # NOT thread-safe: iteration while modifying
5312+ for elem in s:
5313+ process(elem) # another thread may modify s
5314+
5315+ Consider external synchronization when sharing :class: `set ` instances
5316+ across threads. See :ref: `freethreading-python-howto ` for more information.
5317+
52125318
52135319.. _typesmapping :
52145320
0 commit comments