from weakref import WeakSet from threading import Thread from random import random, randrange, shuffle from time import sleep from itertools import count def f1(ws): list(ws) def f2(ws): sleep(random()) list(ws) def g(s): sleep(random()) s.clear() class Obj: pass for c in count(1): # the more things we add to the set # the more work _commit_removals is doing # so the larger the window for another iteration to start s = set(Obj() for _ in range(randrange(100_000, 1_000_000))) ws = WeakSet(s) # we make 2 threads that try iterate the weakset at the same time # (actually we want there to be a slight offset so that the second starts just after the first finishes) # more `f` threads won't necessarily help observe it, as we require a moment where *no* other threads are iterating to hit the race ts = [ Thread(target=f1, args=[ws]), Thread(target=f2, args=[ws]), Thread(target=g, args=[s]), ] shuffle(ts) for t in ts: t.start() for t in ts: t.join() if c % 80 == 0: print() print(".", end="", flush=True) EX_OUTPUT = """\ ............................................................................... ................................................................................ .......Exception in thread Thread-500: Traceback (most recent call last): File "/home/vscode/.pyenv/versions/3.9.6/lib/python3.9/threading.py", line 973, in _bootstrap_inner self.run() File "/home/vscode/.pyenv/versions/3.9.6/lib/python3.9/threading.py", line 910, in run self._target(*self._args, **self._kwargs) File "/home/vscode/threading_weakset_concurrent_iter.py", line 15, in f2 list(ws) File "/home/vscode/.pyenv/versions/3.9.6/lib/python3.9/_weakrefset.py", line 61, in __iter__ for itemref in self.data: RuntimeError: Set changed size during iteration """