| import unittest | |
| from collections import OrderedDict, deque | |
| from copy import copy | |
| from test.support import threading_helper | |
| threading_helper.requires_working_threading(module=True) | |
| class TestDeque(unittest.TestCase): | |
| def test_copy_race(self): | |
| # gh-144809: Test that deque copy is thread safe. It previously | |
| # could raise a "deque mutated during iteration" error. | |
| d = deque(range(100)) | |
| def mutate(): | |
| for i in range(1000): | |
| d.append(i) | |
| if len(d) > 200: | |
| d.popleft() | |
| def copy_loop(): | |
| for _ in range(1000): | |
| copy(d) | |
| threading_helper.run_concurrently([mutate, copy_loop]) | |
| def test_index_race_in_ac(self): | |
| # gh-150750: There was a c_default specified as `Py_SIZE(self)`, | |
| # it was used without a critical section. | |
| d = deque(range(100)) | |
| def index(): | |
| for _ in range(10000): | |
| try: | |
| d.index(50) | |
| except ValueError: | |
| pass | |
| def mutate(): | |
| for _ in range(10000): | |
| d.append(0) | |
| d.clear() | |
| d.extend(range(100)) | |
| d.appendleft(-1) | |
| threading_helper.run_concurrently( | |
| [index, *[mutate for _ in range(3)]], | |
| ) | |
| class TestOrderedDict(unittest.TestCase): | |
| def test_iterator_update_clear_race(self): | |
| # gh-151627: OrderedDict iterator construction must not race with | |
| # concurrent clear()/update() operations that mutate the linked list. | |
| od = OrderedDict((i, i) for i in range(100)) | |
| def mutate(): | |
| for i in range(5000): | |
| od.clear() | |
| od.update(((i, i), (i + 1, i + 1), (i + 2, i + 2))) | |
| def iterate(): | |
| for _ in range(5000): | |
| try: | |
| for _ in od: | |
| pass | |
| list(reversed(od)) | |
| except RuntimeError: | |
| pass | |
| threading_helper.run_concurrently( | |
| [mutate, *[iterate for _ in range(8)]], | |
| ) | |
| if __name__ == "__main__": | |
| unittest.main() |