Skip to content

collections.deque is not thread safe during copy #144809

@yilei

Description

@yilei

Bug report

Bug description:

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

Example code:

import sys
import threading
from collections import deque
from copy import copy

print(f"Python {sys.version}")
print(f"GIL enabled: {sys._is_gil_enabled()}")

d = deque(range(100))
stop = threading.Event()


def mutate():
    i = 0
    while not stop.is_set():
        d.append(i)
        if len(d) > 200:
            d.popleft()
        i += 1


def copy_loop():
    while not stop.is_set():
        copy(d)


barrier = threading.Barrier(5)


def run(fn):
    barrier.wait()
    fn()


threads = [
    threading.Thread(target=run, args=(f,), daemon=True)
    for f in [mutate, mutate, copy_loop, copy_loop]
]
for t in threads:
    t.start()

barrier.wait()

stop.wait(timeout=5)
stop.set()
for t in threads:
    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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions