@@ -342,3 +342,108 @@ thread, iterate over a copy:
342342
343343 Consider external synchronization when sharing :class: `dict ` instances
344344across threads.
345+
346+
347+ .. _thread-safety-set :
348+
349+ Thread safety for set objects
350+ ==============================
351+
352+ The :func: `len ` function is lock-free and :term: `atomic <atomic operation> `.
353+
354+ The following read operation is lock-free. It does not block concurrent
355+ modifications and may observe intermediate states from operations that
356+ hold the per-object lock:
357+
358+ .. code-block ::
359+ :class: good
360+
361+ elem in s # set.__contains__
362+
363+ This operation may compare elements using :meth: `~object.__eq__ `, which can
364+ execute arbitrary Python code. During such comparisons, the set may be
365+ modified by another thread. For built-in types like :class: `str `,
366+ :class: `int `, and :class: `float `, :meth: `!__eq__ ` does not release the
367+ underlying lock during comparisons and this is not a concern.
368+
369+ All other operations from here on hold the per-object lock.
370+
371+ Adding or removing a single element is safe to call from multiple threads
372+ and will not corrupt the set:
373+
374+ .. code-block ::
375+ :class: good
376+
377+ s.add(elem) # add element
378+ s.remove(elem) # remove element, raise if missing
379+ s.discard(elem) # remove element if present
380+ s.pop() # remove and return arbitrary element
381+
382+ These operations also compare elements, so the same :meth: `~object.__eq__ `
383+ considerations as above apply.
384+
385+ The :meth: `~set.copy ` method returns a new object and holds the per-object lock
386+ for the duration so that it is always atomic.
387+
388+ The :meth: `~set.clear ` method holds the lock for its duration. Other
389+ threads cannot observe elements being removed.
390+
391+ The following operations only accept :class: `set ` or :class: `frozenset `
392+ as operands and always lock both objects:
393+
394+ .. code-block ::
395+ :class: good
396+
397+ s |= other # other must be set/frozenset
398+ s &= other # other must be set/frozenset
399+ s -= other # other must be set/frozenset
400+ s ^= other # other must be set/frozenset
401+ s & other # other must be set/frozenset
402+ s | other # other must be set/frozenset
403+ s - other # other must be set/frozenset
404+ s ^ other # other must be set/frozenset
405+
406+ :meth: `set.update `, :meth: `set.union `, :meth: `set.intersection ` and
407+ :meth: `set.difference ` can take multiple iterables as arguments. They all
408+ iterate through all the passed iterables and do the following:
409+
410+ * :meth: `set.update ` and :meth: `set.union ` lock both objects only when
411+ the other operand is a :class: `set `, :class: `frozenset `, or :class: `dict `.
412+ * :meth: `set.intersection ` and :meth: `set.difference ` always try to lock
413+ all objects.
414+
415+ :meth: `set.symmetric_difference ` tries to lock both objects.
416+
417+ The update variants of the above methods also have some differences between
418+ them:
419+
420+ * :meth: `set.difference_update ` and :meth: `set.intersection_update ` try
421+ to lock all objects one-by-one.
422+ * :meth: `set.symmetric_difference_update ` only locks the arguments if it is
423+ of type :class: `set `, :class: `frozenset `, or :class: `dict `.
424+
425+ The following methods always try to lock both objects:
426+
427+ .. code-block ::
428+ :class: good
429+
430+ s.isdisjoint(other) # both locked
431+ s.issubset(other) # both locked
432+ s.issuperset(other) # both locked
433+
434+ Operations that involve multiple accesses, as well as iteration, are never
435+ atomic:
436+
437+ .. code-block ::
438+ :class: bad
439+
440+ # NOT atomic: check-then-act
441+ if elem in s:
442+ s.remove(elem)
443+
444+ # NOT thread-safe: iteration while modifying
445+ for elem in s:
446+ process(elem) # another thread may modify s
447+
448+ Consider external synchronization when sharing :class: `set ` instances
449+ across threads. See :ref: `freethreading-python-howto ` for more information.
0 commit comments