Skip to content

Commit 3a24856

Browse files
authored
gh-123471: make concurrent iteration over itertools.accumulate thread-safe (#144486)
1 parent 6f8867a commit 3a24856

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

Lib/test/test_free_threading/test_itertools.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import unittest
2-
from itertools import batched, chain, combinations_with_replacement, cycle, permutations
2+
from itertools import accumulate, batched, chain, combinations_with_replacement, cycle, permutations
33
from test.support import threading_helper
44

55

@@ -16,6 +16,13 @@ def work_iterator(it):
1616

1717
class ItertoolsThreading(unittest.TestCase):
1818

19+
@threading_helper.reap_threads
20+
def test_accumulate(self):
21+
number_of_iterations = 10
22+
for _ in range(number_of_iterations):
23+
it = accumulate(tuple(range(40)))
24+
threading_helper.run_concurrently(work_iterator, nthreads=10, args=[it])
25+
1926
@threading_helper.reap_threads
2027
def test_batched(self):
2128
number_of_iterations = 10
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make concurrent iteration over :class:`itertools.accumulate` safe under free-threading.

Modules/itertoolsmodule.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3073,7 +3073,7 @@ accumulate_traverse(PyObject *op, visitproc visit, void *arg)
30733073
}
30743074

30753075
static PyObject *
3076-
accumulate_next(PyObject *op)
3076+
accumulate_next_lock_held(PyObject *op)
30773077
{
30783078
accumulateobject *lz = accumulateobject_CAST(op);
30793079
PyObject *val, *newtotal;
@@ -3105,6 +3105,16 @@ accumulate_next(PyObject *op)
31053105
return newtotal;
31063106
}
31073107

3108+
static PyObject *
3109+
accumulate_next(PyObject *op)
3110+
{
3111+
PyObject *result;
3112+
Py_BEGIN_CRITICAL_SECTION(op);
3113+
result = accumulate_next_lock_held(op);
3114+
Py_END_CRITICAL_SECTION()
3115+
return result;
3116+
}
3117+
31083118
static PyType_Slot accumulate_slots[] = {
31093119
{Py_tp_dealloc, accumulate_dealloc},
31103120
{Py_tp_getattro, PyObject_GenericGetAttr},

0 commit comments

Comments
 (0)