from __future__ import annotations import threading import unittest from collections.abc import Iterable class ThreadSafeCounter: """A small integer counter guarded by a lock.""" def __init__(self, initial: int = 0) -> None: self._value = initial self._lock = threading.Lock() def increment(self, amount: int = 1) -> int: # Keep read-modify-write operations atomic. with self._lock: self._value += amount return self._value def decrement(self, amount: int = 1) -> int: return self.increment(-amount) @property def value(self) -> int: # Return a consistent snapshot. with self._lock: return self._value def reset(self, value: int = 0) -> int: with self._lock: self._value = value return self._value def run_many(counter: ThreadSafeCounter, increments: Iterable[int]) -> None: for amount in increments: counter.increment(amount) class ThreadSafeCounterTests(unittest.TestCase): def test_basic_operations(self) -> None: counter = ThreadSafeCounter(10) self.assertEqual(counter.increment(), 11) self.assertEqual(counter.increment(4), 15) self.assertEqual(counter.decrement(5), 10) self.assertEqual(counter.reset(), 0) self.assertEqual(counter.value, 0) def test_concurrent_increments(self) -> None: counter = ThreadSafeCounter() thread_count = 8 increments_per_thread = 10_000 threads = [ threading.Thread( target=run_many, args=(counter, [1] * increments_per_thread), ) for _ in range(thread_count) ] for thread in threads: thread.start() for thread in threads: thread.join() self.assertEqual(counter.value, thread_count * increments_per_thread) if __name__ == "__main__": unittest.main()