Skip to content

Commit 6370bc4

Browse files
committed
Make permutations thread-safe
1 parent 8139046 commit 6370bc4

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

Lib/test/test_free_threading/test_itertools.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import unittest
22
from threading import Thread, Barrier
3-
from itertools import batched, chain, combinations_with_replacement, cycle
3+
from itertools import batched, chain, combinations_with_replacement, cycle, permutations
44
from test.support import threading_helper
55

66

@@ -92,7 +92,7 @@ def work(it):
9292
@threading_helper.reap_threads
9393
def test_combinations_with_replacement(self):
9494
number_of_threads = 6
95-
number_of_iterations = 50
95+
number_of_iterations = 36
9696
data = tuple(range(2))
9797

9898
barrier = Barrier(number_of_threads)
@@ -116,6 +116,33 @@ def work(it):
116116

117117
barrier.reset()
118118

119+
@threading_helper.reap_threads
120+
def test_permutations(self):
121+
number_of_threads = 6
122+
number_of_iterations = 36
123+
data = tuple(range(4))
124+
125+
barrier = Barrier(number_of_threads)
126+
def work(it):
127+
barrier.wait()
128+
while True:
129+
try:
130+
next(it)
131+
except StopIteration:
132+
break
133+
134+
for _ in range(number_of_iterations):
135+
perm_iterator = permutations(data, 2)
136+
worker_threads = []
137+
for _ in range(number_of_threads):
138+
worker_threads.append(
139+
Thread(target=work, args=[perm_iterator]))
140+
141+
with threading_helper.start_threads(worker_threads):
142+
pass
143+
144+
barrier.reset()
145+
119146

120147
if __name__ == "__main__":
121148
unittest.main()

Modules/itertoolsmodule.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2856,7 +2856,7 @@ permutations_traverse(PyObject *op, visitproc visit, void *arg)
28562856
}
28572857

28582858
static PyObject *
2859-
permutations_next(PyObject *op)
2859+
permutations_next_lock_held(PyObject *op)
28602860
{
28612861
permutationsobject *po = permutationsobject_CAST(op);
28622862
PyObject *elem;
@@ -2946,6 +2946,16 @@ permutations_next(PyObject *op)
29462946
return NULL;
29472947
}
29482948

2949+
static PyObject *
2950+
permutations_next(PyObject *op)
2951+
{
2952+
PyObject *result;
2953+
Py_BEGIN_CRITICAL_SECTION(op);
2954+
result = permutations_next_lock_held(op);
2955+
Py_END_CRITICAL_SECTION()
2956+
return result;
2957+
}
2958+
29492959
static PyMethodDef permuations_methods[] = {
29502960
{"__sizeof__", permutations_sizeof, METH_NOARGS, sizeof_doc},
29512961
{NULL, NULL} /* sentinel */

0 commit comments

Comments
 (0)