#10218: return timeout status from Condition.wait, mirroring other primitives' behavior.

This commit is contained in:
Georg Brandl 2010-10-28 09:03:20 +00:00
parent cbb9421347
commit b9a4391754
4 changed files with 29 additions and 13 deletions

View file

@ -574,6 +574,12 @@ needs to wake up one consumer thread.
interface is then used to restore the recursion level when the lock is interface is then used to restore the recursion level when the lock is
reacquired. reacquired.
The return value is ``True`` unless a given *timeout* expired, in which
case it is ``False``.
.. versionchanged:: 3.2
Previously, the method always returned ``None``.
.. method:: notify() .. method:: notify()
Wake up a thread waiting on this condition, if any. If the calling thread Wake up a thread waiting on this condition, if any. If the calling thread

View file

@ -375,13 +375,13 @@ class ConditionTests(BaseTestCase):
phase_num = 0 phase_num = 0
def f(): def f():
cond.acquire() cond.acquire()
cond.wait() result = cond.wait()
cond.release() cond.release()
results1.append(phase_num) results1.append((result, phase_num))
cond.acquire() cond.acquire()
cond.wait() result = cond.wait()
cond.release() cond.release()
results2.append(phase_num) results2.append((result, phase_num))
b = Bunch(f, N) b = Bunch(f, N)
b.wait_for_started() b.wait_for_started()
_wait() _wait()
@ -394,7 +394,7 @@ class ConditionTests(BaseTestCase):
cond.release() cond.release()
while len(results1) < 3: while len(results1) < 3:
_wait() _wait()
self.assertEqual(results1, [1] * 3) self.assertEqual(results1, [(True, 1)] * 3)
self.assertEqual(results2, []) self.assertEqual(results2, [])
# Notify 5 threads: they might be in their first or second wait # Notify 5 threads: they might be in their first or second wait
cond.acquire() cond.acquire()
@ -404,8 +404,8 @@ class ConditionTests(BaseTestCase):
cond.release() cond.release()
while len(results1) + len(results2) < 8: while len(results1) + len(results2) < 8:
_wait() _wait()
self.assertEqual(results1, [1] * 3 + [2] * 2) self.assertEqual(results1, [(True, 1)] * 3 + [(True, 2)] * 2)
self.assertEqual(results2, [2] * 3) self.assertEqual(results2, [(True, 2)] * 3)
# Notify all threads: they are all in their second wait # Notify all threads: they are all in their second wait
cond.acquire() cond.acquire()
cond.notify_all() cond.notify_all()
@ -414,8 +414,8 @@ class ConditionTests(BaseTestCase):
cond.release() cond.release()
while len(results2) < 5: while len(results2) < 5:
_wait() _wait()
self.assertEqual(results1, [1] * 3 + [2] * 2) self.assertEqual(results1, [(True, 1)] * 3 + [(True,2)] * 2)
self.assertEqual(results2, [2] * 3 + [3] * 2) self.assertEqual(results2, [(True, 2)] * 3 + [(True, 3)] * 2)
b.wait_for_finished() b.wait_for_finished()
def test_notify(self): def test_notify(self):
@ -431,14 +431,20 @@ class ConditionTests(BaseTestCase):
def f(): def f():
cond.acquire() cond.acquire()
t1 = time.time() t1 = time.time()
cond.wait(0.5) result = cond.wait(0.5)
t2 = time.time() t2 = time.time()
cond.release() cond.release()
results.append(t2 - t1) results.append((t2 - t1, result))
Bunch(f, N).wait_for_finished() Bunch(f, N).wait_for_finished()
self.assertEqual(len(results), 5) self.assertEqual(len(results), N)
for dt in results: for dt, result in results:
self.assertTimeout(dt, 0.5) self.assertTimeout(dt, 0.5)
# Note that conceptually (that"s the condition variable protocol)
# a wait() may succeed even if no one notifies us and before any
# timeout occurs. Spurious wakeups can occur.
# This makes it hard to verify the result value.
# In practice, this implementation has no spurious wakeups.
self.assertFalse(result)
class BaseSemaphoreTests(BaseTestCase): class BaseSemaphoreTests(BaseTestCase):

View file

@ -232,6 +232,7 @@ class _Condition(_Verbose):
try: # restore state no matter what (e.g., KeyboardInterrupt) try: # restore state no matter what (e.g., KeyboardInterrupt)
if timeout is None: if timeout is None:
waiter.acquire() waiter.acquire()
gotit = True
if __debug__: if __debug__:
self._note("%s.wait(): got it", self) self._note("%s.wait(): got it", self)
else: else:
@ -249,6 +250,7 @@ class _Condition(_Verbose):
else: else:
if __debug__: if __debug__:
self._note("%s.wait(%s): got it", self, timeout) self._note("%s.wait(%s): got it", self, timeout)
return gotit
finally: finally:
self._acquire_restore(saved_state) self._acquire_restore(saved_state)

View file

@ -51,6 +51,8 @@ Core and Builtins
Library Library
------- -------
- Issue #10218: Return timeout status from ``Condition.wait`` in threading.
- Issue #7351: Add ``zipfile.BadZipFile`` spelling of the exception name - Issue #7351: Add ``zipfile.BadZipFile`` spelling of the exception name
and deprecate the old name ``zipfile.BadZipfile``. and deprecate the old name ``zipfile.BadZipfile``.