New GitHub issue #95826 from mcclurem:<br>
<hr>
<pre>
Current Python.org docs for `multiprocessing.Event` link directly to `threading.Event`
The documents for `threading.Event.wait` read (emphasis mine)
> This method returns True if and only if the internal flag has been set to 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.**
It appears that a race condition exists in the multiprocessing implementation but not in the threading implementation.
If we implement a child process that just does a set/clear on an event over and over (as a heartbeat), then in the parent process do a wait() on that event (with extremely long timeout), we would expect to never see a timeout.
I've attached the proof of concept below showing how both threading.Event and multiprocessing.Event yield different results.
Possible cousin bug: #85772
Observed on:
- Mac OS 12.3 Monterey
- Apple M1 Max MacBook Pro
- Homebrew python: Python 3.9.13 (main, May 24 2022, 21:13:54) [Clang 13.0.0 (clang-1300.0.29.30)]
```python
#!/usr/bin/env python3
import multiprocessing
import threading
class SimpleRepro:
def __init__(self, use_thread=False):
if use_thread:
self.heartbeat_event = threading.Event()
self.shutdown_event = threading.Event()
self.child_proc = threading.Thread(target=self.child_process)
else:
self.heartbeat_event = multiprocessing.Event()
self.shutdown_event = multiprocessing.Event()
self.child_proc = multiprocessing.Process(target=self.child_process, daemon=True)
self.child_proc.start()
def child_process(self):
while True:
if self.shutdown_event.is_set():
return
self.heartbeat_event.set()
self.heartbeat_event.clear()
def test_heartbeat(self):
any_failures=False
for i in range(10000):
success = self.heartbeat_event.wait(100)
if not success:
print(f"Failed at iteration {i}")
any_failures = True
self.shutdown_event.set()
if not any_failures:
print("Successfully tested 10000 times without failure")
if __name__ == '__main__':
print("Testing with multiprocessing.Event")
foo = SimpleRepro(use_thread=False)
foo.test_heartbeat()
print("Testing with threading.Event")
foo = SimpleRepro(use_thread=True)
foo.test_heartbeat()
```
</pre>
<hr>
<a href="https://github.com/python/cpython/issues/95826">View on GitHub</a>
<p>Labels: </p>
<p>Assignee: </p>