Description
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)]
#!/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()
Metadata
Metadata
Assignees
Projects
Status