Commit 61d28d6a authored by Charles-François Natali's avatar Charles-François Natali

Issue #13502: threading: Fix a race condition in Event.wait() that made it

return False when the event was set and cleared right after.
parents 5e60857e ded0348c
...@@ -804,8 +804,10 @@ An event object manages an internal flag that can be set to true with the ...@@ -804,8 +804,10 @@ An event object manages an internal flag that can be set to true with the
floating point number specifying a timeout for the operation in seconds floating point number specifying a timeout for the operation in seconds
(or fractions thereof). (or fractions thereof).
This method returns the internal flag on exit, so it will always return This method returns true if and only if the internal flag has been set to
``True`` except if a timeout is given and the operation times out. true, either before the wait call or after the wait starts, so it will
always return ``True`` except if a timeout is given and the operation
times out.
.. versionchanged:: 3.1 .. versionchanged:: 3.1
Previously, the method always returned ``None``. Previously, the method always returned ``None``.
......
...@@ -353,6 +353,22 @@ class EventTests(BaseTestCase): ...@@ -353,6 +353,22 @@ class EventTests(BaseTestCase):
for r, dt in results2: for r, dt in results2:
self.assertTrue(r) self.assertTrue(r)
def test_set_and_clear(self):
# Issue #13502: check that wait() returns true even when the event is
# cleared before the waiting thread is woken up.
evt = self.eventtype()
results = []
N = 5
def f():
results.append(evt.wait(1))
b = Bunch(f, N)
b.wait_for_started()
time.sleep(0.5)
evt.set()
evt.clear()
b.wait_for_finished()
self.assertEqual(results, [True] * N)
class ConditionTests(BaseTestCase): class ConditionTests(BaseTestCase):
""" """
......
...@@ -408,9 +408,10 @@ class Event(_Verbose): ...@@ -408,9 +408,10 @@ class Event(_Verbose):
def wait(self, timeout=None): def wait(self, timeout=None):
self._cond.acquire() self._cond.acquire()
try: try:
if not self._flag: signaled = self._flag
self._cond.wait(timeout) if not signaled:
return self._flag signaled = self._cond.wait(timeout)
return signaled
finally: finally:
self._cond.release() self._cond.release()
......
...@@ -422,6 +422,9 @@ Core and Builtins ...@@ -422,6 +422,9 @@ Core and Builtins
Library Library
------- -------
- Issue #13502: threading: Fix a race condition in Event.wait() that made it
return False when the event was set and cleared right after.
- Issue #9993: When the source and destination are on different filesystems, - Issue #9993: When the source and destination are on different filesystems,
and the source is a symlink, shutil.move() now recreates a symlink on the and the source is a symlink, shutil.move() now recreates a symlink on the
destination instead of copying the file contents. Patch by Jonathan Niehof destination instead of copying the file contents. Patch by Jonathan Niehof
......
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