Issue #850728: Add a *timeout* parameter to the `acquire()` method of

`threading.Semaphore` objects.  Original patch by Torsten Landschoff.
This commit is contained in:
Antoine Pitrou 2010-04-17 23:51:58 +00:00
parent 2d9cb9c1cb
commit 0454af9b54
5 changed files with 40 additions and 9 deletions

View File

@ -596,7 +596,7 @@ waiting until some other thread calls :meth:`release`.
defaults to ``1``. If the *value* given is less than 0, :exc:`ValueError` is
raised.
.. method:: acquire(blocking=True)
.. method:: acquire(blocking=True, timeout=None)
Acquire a semaphore.
@ -607,14 +607,18 @@ waiting until some other thread calls :meth:`release`.
interlocking so that if multiple :meth:`acquire` calls are blocked,
:meth:`release` will wake exactly one of them up. The implementation may
pick one at random, so the order in which blocked threads are awakened
should not be relied on. There is no return value in this case.
When invoked with *blocking* set to true, do the same thing as when called
without arguments, and return true.
should not be relied on. Returns true (or blocks indefinitely).
When invoked with *blocking* set to false, do not block. If a call
without an argument would block, return false immediately; otherwise, do
the same thing as when called without arguments, and return true.
without an argument would block, return false immediately; otherwise,
do the same thing as when called without arguments, and return true.
When invoked with a *timeout* other than None, it will block for at
most *timeout* seconds. If acquire does not complete successfully in
that interval, return false. Return true otherwise.
.. versionchanged:: 3.2
The *timeout* parameter is new.
.. method:: release()

View File

@ -521,6 +521,19 @@ class BaseSemaphoreTests(BaseTestCase):
# ordered.
self.assertEqual(sorted(results), [False] * 7 + [True] * 3 )
def test_acquire_timeout(self):
sem = self.semtype(2)
self.assertRaises(ValueError, sem.acquire, False, timeout=1.0)
self.assertTrue(sem.acquire(timeout=0.005))
self.assertTrue(sem.acquire(timeout=0.005))
self.assertFalse(sem.acquire(timeout=0.005))
sem.release()
self.assertTrue(sem.acquire(timeout=0.005))
t = time.time()
self.assertFalse(sem.acquire(timeout=0.5))
dt = time.time() - t
self.assertTimeout(dt, 0.5)
def test_default_value(self):
# The default initial value is 1.
sem = self.semtype()

View File

@ -290,8 +290,11 @@ class _Semaphore(_Verbose):
self._cond = Condition(Lock())
self._value = value
def acquire(self, blocking=True):
def acquire(self, blocking=True, timeout=None):
if not blocking and timeout is not None:
raise ValueError("can't specify timeout for non-blocking acquire")
rc = False
endtime = None
self._cond.acquire()
while self._value == 0:
if not blocking:
@ -299,7 +302,14 @@ class _Semaphore(_Verbose):
if __debug__:
self._note("%s.acquire(%s): blocked waiting, value=%s",
self, blocking, self._value)
self._cond.wait()
if timeout is not None:
if endtime is None:
endtime = _time() + timeout
else:
timeout = endtime - _time()
if timeout <= 0:
break
self._cond.wait(timeout)
else:
self._value = self._value - 1
if __debug__:

View File

@ -431,6 +431,7 @@ Ivan Krstić
Andrew Kuchling
Vladimir Kushnir
Cameron Laird
Torsten Landschoff
Tino Lange
Andrew Langmead
Detlef Lannert

View File

@ -315,6 +315,9 @@ C-API
Library
-------
- Issue #850728: Add a *timeout* parameter to the `acquire()` method of
`threading.Semaphore` objects. Patch by Torsten Landschoff.
- Issue #8322: Add a *ciphers* argument to SSL sockets, so as to change the
available cipher list. Helps fix test_ssl with OpenSSL 1.0.0.