From b9a439175451903ab77c71e5b2020dbd1671a77e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 28 Oct 2010 09:03:20 +0000 Subject: [PATCH] #10218: return timeout status from Condition.wait, mirroring other primitives' behavior. --- Doc/library/threading.rst | 6 ++++++ Lib/test/lock_tests.py | 32 +++++++++++++++++++------------- Lib/threading.py | 2 ++ Misc/NEWS | 2 ++ 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index 3e2e1e3758a..7c8f709d7a4 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -574,6 +574,12 @@ needs to wake up one consumer thread. interface is then used to restore the recursion level when the lock is 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() Wake up a thread waiting on this condition, if any. If the calling thread diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py index a288176fa99..1ff6af0a7ab 100644 --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -375,13 +375,13 @@ class ConditionTests(BaseTestCase): phase_num = 0 def f(): cond.acquire() - cond.wait() + result = cond.wait() cond.release() - results1.append(phase_num) + results1.append((result, phase_num)) cond.acquire() - cond.wait() + result = cond.wait() cond.release() - results2.append(phase_num) + results2.append((result, phase_num)) b = Bunch(f, N) b.wait_for_started() _wait() @@ -394,7 +394,7 @@ class ConditionTests(BaseTestCase): cond.release() while len(results1) < 3: _wait() - self.assertEqual(results1, [1] * 3) + self.assertEqual(results1, [(True, 1)] * 3) self.assertEqual(results2, []) # Notify 5 threads: they might be in their first or second wait cond.acquire() @@ -404,8 +404,8 @@ class ConditionTests(BaseTestCase): cond.release() while len(results1) + len(results2) < 8: _wait() - self.assertEqual(results1, [1] * 3 + [2] * 2) - self.assertEqual(results2, [2] * 3) + self.assertEqual(results1, [(True, 1)] * 3 + [(True, 2)] * 2) + self.assertEqual(results2, [(True, 2)] * 3) # Notify all threads: they are all in their second wait cond.acquire() cond.notify_all() @@ -414,8 +414,8 @@ class ConditionTests(BaseTestCase): cond.release() while len(results2) < 5: _wait() - self.assertEqual(results1, [1] * 3 + [2] * 2) - self.assertEqual(results2, [2] * 3 + [3] * 2) + self.assertEqual(results1, [(True, 1)] * 3 + [(True,2)] * 2) + self.assertEqual(results2, [(True, 2)] * 3 + [(True, 3)] * 2) b.wait_for_finished() def test_notify(self): @@ -431,14 +431,20 @@ class ConditionTests(BaseTestCase): def f(): cond.acquire() t1 = time.time() - cond.wait(0.5) + result = cond.wait(0.5) t2 = time.time() cond.release() - results.append(t2 - t1) + results.append((t2 - t1, result)) Bunch(f, N).wait_for_finished() - self.assertEqual(len(results), 5) - for dt in results: + self.assertEqual(len(results), N) + for dt, result in results: 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): diff --git a/Lib/threading.py b/Lib/threading.py index dd6e91d37b3..238a5c4508f 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -232,6 +232,7 @@ class _Condition(_Verbose): try: # restore state no matter what (e.g., KeyboardInterrupt) if timeout is None: waiter.acquire() + gotit = True if __debug__: self._note("%s.wait(): got it", self) else: @@ -249,6 +250,7 @@ class _Condition(_Verbose): else: if __debug__: self._note("%s.wait(%s): got it", self, timeout) + return gotit finally: self._acquire_restore(saved_state) diff --git a/Misc/NEWS b/Misc/NEWS index b1e40ad5dbe..9bbeec268c9 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -51,6 +51,8 @@ Core and Builtins Library ------- +- Issue #10218: Return timeout status from ``Condition.wait`` in threading. + - Issue #7351: Add ``zipfile.BadZipFile`` spelling of the exception name and deprecate the old name ``zipfile.BadZipfile``.