https://github.com/python/cpython/commit/3a248564470075cb8c7b8a75fe7ba61f7ea341b2
commit: 3a248564470075cb8c7b8a75fe7ba61f7ea341b2
branch: main
author: Pieter Eendebak <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2026-03-16T08:53:37Z
summary:
gh-123471: make concurrent iteration over itertools.accumulate thread-safe
(#144486)
files:
A Misc/NEWS.d/next/Library/2026-02-04-20-30-59.gh-issue-123471.1dnPvs.rst
M Lib/test/test_free_threading/test_itertools.py
M Modules/itertoolsmodule.c
diff --git a/Lib/test/test_free_threading/test_itertools.py
b/Lib/test/test_free_threading/test_itertools.py
index bb6047e8669475..20135dd3165acf 100644
--- a/Lib/test/test_free_threading/test_itertools.py
+++ b/Lib/test/test_free_threading/test_itertools.py
@@ -1,5 +1,5 @@
import unittest
-from itertools import batched, chain, combinations_with_replacement, cycle,
permutations
+from itertools import accumulate, batched, chain,
combinations_with_replacement, cycle, permutations
from test.support import threading_helper
@@ -16,6 +16,13 @@ def work_iterator(it):
class ItertoolsThreading(unittest.TestCase):
+ @threading_helper.reap_threads
+ def test_accumulate(self):
+ number_of_iterations = 10
+ for _ in range(number_of_iterations):
+ it = accumulate(tuple(range(40)))
+ threading_helper.run_concurrently(work_iterator, nthreads=10,
args=[it])
+
@threading_helper.reap_threads
def test_batched(self):
number_of_iterations = 10
diff --git
a/Misc/NEWS.d/next/Library/2026-02-04-20-30-59.gh-issue-123471.1dnPvs.rst
b/Misc/NEWS.d/next/Library/2026-02-04-20-30-59.gh-issue-123471.1dnPvs.rst
new file mode 100644
index 00000000000000..d650103e28ee68
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-02-04-20-30-59.gh-issue-123471.1dnPvs.rst
@@ -0,0 +1 @@
+Make concurrent iteration over :class:`itertools.accumulate` safe under
free-threading.
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index bc25bf6bfc1bd2..b37256c7928bad 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -3073,7 +3073,7 @@ accumulate_traverse(PyObject *op, visitproc visit, void
*arg)
}
static PyObject *
-accumulate_next(PyObject *op)
+accumulate_next_lock_held(PyObject *op)
{
accumulateobject *lz = accumulateobject_CAST(op);
PyObject *val, *newtotal;
@@ -3105,6 +3105,16 @@ accumulate_next(PyObject *op)
return newtotal;
}
+static PyObject *
+accumulate_next(PyObject *op)
+{
+ PyObject *result;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ result = accumulate_next_lock_held(op);
+ Py_END_CRITICAL_SECTION()
+ return result;
+}
+
static PyType_Slot accumulate_slots[] = {
{Py_tp_dealloc, accumulate_dealloc},
{Py_tp_getattro, PyObject_GenericGetAttr},
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]