Skip to content

collections.deque is not atomic during copy #144809

Description

@yilei

[Edit: This bug was originally reported as "not thread safe", and updated to "not atomic"]

Bug report

Bug description:

In free-threaded mode, calling copy on collections.deque is not thread safe atomic and can raise RuntimeError: deque mutated during iteration errors.

Example code:

importsysimportthreadingfromcollectionsimportdequefromcopyimportcopyprint(f"Python {sys.version}")
print(f"GIL enabled: {sys._is_gil_enabled()}")
d=deque(range(100))
stop=threading.Event()
defmutate():
i=0whilenotstop.is_set():
d.append(i)
iflen(d) >200:
d.popleft()
i+=1defcopy_loop():
whilenotstop.is_set():
copy(d)
barrier=threading.Barrier(5)
defrun(fn):
barrier.wait()
fn()
threads= [
threading.Thread(target=run, args=(f,), daemon=True)
forfin [mutate, mutate, copy_loop, copy_loop]
]
fortinthreads:
t.start()
barrier.wait()
stop.wait(timeout=5)
stop.set()
fortinthreads:
t.join(timeout=5)
print("Done")

Running under free-threaded build:

❯ ./python /tmp/deque.py
Python 3.15.0a6+ free-threading build (heads/main:945bf8ce1bf, Feb 13 2026, 22:04:08) [GCC 11.4.0]
GIL enabled: False
Exception in thread Thread-4 (run):
Exception in thread Thread-3 (run):
Traceback (most recent call last):
Traceback (most recent call last):
File "cpython/Lib/threading.py", line 1075, in _bootstrap_inner
self._context.run(self.run)
~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "cpython/Lib/threading.py", line 1017, in run
self._target(*self._args, **self._kwargs)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/deque.py", line 32, in run
fn()
~~^^
File "/tmp/deque.py", line 24, in copy_loop
copy(d)
~~~~^^^
File "cpython/Lib/copy.py", line 82, in copy
return copier(x)
RuntimeError: deque mutated during iteration
File "cpython/Lib/threading.py", line 1075, in _bootstrap_inner
self._context.run(self.run)
~~~~~~~~~~~~~~~~~^^^^^^^^^^
File "cpython/Lib/threading.py", line 1017, in run
self._target(*self._args, **self._kwargs)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/deque.py", line 32, in run
fn()
~~^^
File "/tmp/deque.py", line 24, in copy_loop
copy(d)
~~~~^^^
File "cpython/Lib/copy.py", line 82, in copy
return copier(x)
RuntimeError: deque mutated during iteration
Done

CPython versions tested on:

CPython main branch, 3.14

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions