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 defaults to ``1``. If the *value* given is less than 0, :exc:`ValueError` is
raised. raised.
.. method:: acquire(blocking=True) .. method:: acquire(blocking=True, timeout=None)
Acquire a semaphore. 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, interlocking so that if multiple :meth:`acquire` calls are blocked,
:meth:`release` will wake exactly one of them up. The implementation may :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 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. should not be relied on. Returns true (or blocks indefinitely).
When invoked with *blocking* set to true, do the same thing as when called
without arguments, and return true.
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, do without an argument would block, return false immediately; otherwise,
the same thing as when called without arguments, and return true. 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() .. method:: release()

View file

@ -521,6 +521,19 @@ class BaseSemaphoreTests(BaseTestCase):
# ordered. # ordered.
self.assertEqual(sorted(results), [False] * 7 + [True] * 3 ) 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): def test_default_value(self):
# The default initial value is 1. # The default initial value is 1.
sem = self.semtype() sem = self.semtype()

View file

@ -290,8 +290,11 @@ class _Semaphore(_Verbose):
self._cond = Condition(Lock()) self._cond = Condition(Lock())
self._value = value 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 rc = False
endtime = None
self._cond.acquire() self._cond.acquire()
while self._value == 0: while self._value == 0:
if not blocking: if not blocking:
@ -299,7 +302,14 @@ class _Semaphore(_Verbose):
if __debug__: if __debug__:
self._note("%s.acquire(%s): blocked waiting, value=%s", self._note("%s.acquire(%s): blocked waiting, value=%s",
self, blocking, self._value) 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: else:
self._value = self._value - 1 self._value = self._value - 1
if __debug__: if __debug__:

View file

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

View file

@ -315,6 +315,9 @@ C-API
Library 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 - 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. available cipher list. Helps fix test_ssl with OpenSSL 1.0.0.