Skip to content

Commit 5236b02

Browse files
authored
GH-116738: document thread-safety of bisect (GH-136555)
1 parent 98d462c commit 5236b02

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

Doc/library/bisect.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ method to determine whether a value has been found. Instead, the
2424
functions only call the :meth:`~object.__lt__` method and will return an insertion
2525
point between values in an array.
2626

27+
.. note::
28+
29+
The functions in this module are not thread-safe. If multiple threads
30+
concurrently use :mod:`bisect` functions on the same sequence, this
31+
may result in undefined behaviour. Likewise, if the provided sequence
32+
is mutated by a different thread while a :mod:`bisect` function
33+
is operating on it, the result is undefined. For example, using
34+
:py:func:`~bisect.insort_left` on the same list from multiple threads
35+
may result in the list becoming unsorted.
36+
2737
.. _bisect functions:
2838

2939
The following functions are provided:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import unittest
2+
from test.support import import_helper, threading_helper
3+
import random
4+
5+
py_bisect = import_helper.import_fresh_module('bisect', blocked=['_bisect'])
6+
c_bisect = import_helper.import_fresh_module('bisect', fresh=['_bisect'])
7+
8+
9+
NTHREADS = 4
10+
OBJECT_COUNT = 500
11+
12+
13+
class TestBase:
14+
def do_racing_insort(self, insert_method):
15+
def insert(data):
16+
for _ in range(OBJECT_COUNT):
17+
x = random.randint(-OBJECT_COUNT, OBJECT_COUNT)
18+
insert_method(data, x)
19+
20+
data = list(range(OBJECT_COUNT))
21+
threading_helper.run_concurrently(
22+
worker_func=insert, args=(data,), nthreads=NTHREADS
23+
)
24+
if False:
25+
# These functions are not thread-safe and so the list can become
26+
# unsorted. However, we don't want Python to crash if these
27+
# functions are used concurrently on the same sequence. This
28+
# should also not produce any TSAN warnings.
29+
self.assertTrue(self.is_sorted_ascending(data))
30+
31+
def test_racing_insert_right(self):
32+
self.do_racing_insort(self.mod.insort_right)
33+
34+
def test_racing_insert_left(self):
35+
self.do_racing_insort(self.mod.insort_left)
36+
37+
@staticmethod
38+
def is_sorted_ascending(lst):
39+
"""
40+
Check if the list is sorted in ascending order (non-decreasing).
41+
"""
42+
return all(lst[i - 1] <= lst[i] for i in range(1, len(lst)))
43+
44+
45+
@threading_helper.requires_working_threading()
46+
class TestPyBisect(unittest.TestCase, TestBase):
47+
mod = py_bisect
48+
49+
50+
@threading_helper.requires_working_threading()
51+
class TestCBisect(unittest.TestCase, TestBase):
52+
mod = c_bisect
53+
54+
55+
if __name__ == "__main__":
56+
unittest.main()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy