Commit a0374dd3 authored by Garrett Berg's avatar Garrett Berg Committed by Andrew Svetlov

bpo-32208: update threading.Semaphore docs and add unit test (#4709)

* fix issue32208: update threading.Semaphore docs and add unit test to validate correct behavior

* add test for blocking

* Update threading.rst

* semaphore: remove documentation validation tests and move 'return value' test to BaseSemaphore
parent 961dbe05
...@@ -684,8 +684,8 @@ Semaphores also support the :ref:`context management protocol <with-locks>`. ...@@ -684,8 +684,8 @@ Semaphores also support the :ref:`context management protocol <with-locks>`.
.. class:: Semaphore(value=1) .. class:: Semaphore(value=1)
This class implements semaphore objects. A semaphore manages a counter This class implements semaphore objects. A semaphore manages an atomic
representing the number of :meth:`release` calls minus the number of counter representing the number of :meth:`release` calls minus the number of
:meth:`acquire` calls, plus an initial value. The :meth:`acquire` method :meth:`acquire` calls, plus an initial value. The :meth:`acquire` method
blocks if necessary until it can return without making the counter negative. blocks if necessary until it can return without making the counter negative.
If not given, *value* defaults to 1. If not given, *value* defaults to 1.
...@@ -701,19 +701,19 @@ Semaphores also support the :ref:`context management protocol <with-locks>`. ...@@ -701,19 +701,19 @@ Semaphores also support the :ref:`context management protocol <with-locks>`.
Acquire a semaphore. Acquire a semaphore.
When invoked without arguments: if the internal counter is larger than When invoked without arguments:
zero on entry, decrement it by one and return immediately. If it is zero
on entry, block, waiting until some other thread has called * If the internal counter is larger than zero on entry, decrement it by
:meth:`~Semaphore.release` to make it larger than zero. This is done one and return true immediately.
with proper interlocking so that if multiple :meth:`acquire` calls are * If the internal counter is zero on entry, block until awoken by a call to
blocked, :meth:`~Semaphore.release` will wake exactly one of them up. :meth:`~Semaphore.release`. Once awoken (and the counter is greater
The implementation may pick one at random, so the order in which than 0), decrement the counter by 1 and return true. Exactly one
blocked threads are awakened should not be relied on. Returns thread will be awoken by each call to :meth:`~Semaphore.release`. The
true (or blocks indefinitely). order in which threads are awoken should not be relied on.
When invoked with *blocking* set to false, do not block. If a call When invoked with *blocking* set to false, do not block. If a call
without an argument would block, return false immediately; otherwise, without an argument would block, return false immediately; otherwise, do
do the same thing as when called without arguments, and return true. the same thing as when called without arguments, and return true.
When invoked with a *timeout* other than ``None``, it will block for at When invoked with a *timeout* other than ``None``, it will block for at
most *timeout* seconds. If acquire does not complete successfully in most *timeout* seconds. If acquire does not complete successfully in
......
...@@ -629,13 +629,14 @@ class BaseSemaphoreTests(BaseTestCase): ...@@ -629,13 +629,14 @@ class BaseSemaphoreTests(BaseTestCase):
sem = self.semtype(7) sem = self.semtype(7)
sem.acquire() sem.acquire()
N = 10 N = 10
sem_results = []
results1 = [] results1 = []
results2 = [] results2 = []
phase_num = 0 phase_num = 0
def f(): def f():
sem.acquire() sem_results.append(sem.acquire())
results1.append(phase_num) results1.append(phase_num)
sem.acquire() sem_results.append(sem.acquire())
results2.append(phase_num) results2.append(phase_num)
b = Bunch(f, 10) b = Bunch(f, 10)
b.wait_for_started() b.wait_for_started()
...@@ -659,6 +660,7 @@ class BaseSemaphoreTests(BaseTestCase): ...@@ -659,6 +660,7 @@ class BaseSemaphoreTests(BaseTestCase):
# Final release, to let the last thread finish # Final release, to let the last thread finish
sem.release() sem.release()
b.wait_for_finished() b.wait_for_finished()
self.assertEqual(sem_results, [True] * (6 + 7 + 6 + 1))
def test_try_acquire(self): def test_try_acquire(self):
sem = self.semtype(2) sem = self.semtype(2)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment