I'm trying to solve this LeetCode problem, Print Zero Even Odd:
I've attempted the following solution using threading.Condition
objects:
import threading
from typing import Callable, Optional
class ZeroEvenOdd:
def __init__(self, n: int):
self.n = n
self.i = 0
self.last_printed: Optional[int] = None
self.condition = threading.Condition()
def zero(self, printNumber: Callable[[int], None]) -> None:
with self.condition:
self.condition.wait_for(lambda: self.last_printed is None or self.last_printed > 0)
if self.done:
return
printNumber(0)
self.last_printed = 0
self.i += 1
self.condition.notify_all()
def even(self, printNumber: Callable[[int], None]) -> None:
with self.condition:
self.condition.wait_for(lambda: self.last_printed == 0 and self.i % 2 == 0)
if self.done:
return
self._print_and_notify()
def odd(self, printNumber: Callable[[int], None]) -> None:
with self.condition:
self.condition.wait_for(lambda: self.last_printed == 0 and self.i % 2 == 1)
if self.done:
return
self._print_and_notify()
def _print_and_notify(self) -> None:
printNumber(self.i)
self.last_printed = self.i
self.condition.notify_all()
@property
def done(self) -> bool:
if self.last_printed is not None and self.last_printed >= self.n:
self.condition.release()
self.condition.notify_all()
return True
return False
def printNumber(x: int) -> None:
print(x)
zero_even_odd = ZeroEvenOdd(n=5)
threadA = threading.Thread(target=zero_even_odd.zero, args=(printNumber,))
threadB = threading.Thread(target=zero_even_odd.even, args=(printNumber,))
threadC = threading.Thread(target=zero_even_odd.odd, args=(printNumber,))
if __name__ == "__main__":
threadA.start()
threadB.start()
threadC.start()
However, what I find when I run this is that it prints 0
, then 1
and then hangs indefinitely:
> python print_zero_even_odd.py
0
1
^CException ignored in: <module 'threading' from '/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py'>
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 1308, in _shutdown
lock.acquire()
KeyboardInterrupt
I'm a bit stumped why, after odd()
has been called the first time, zero()
is not called again. After all, after printing the number 1
in odd()
, self.last_printed
gets set to 1
, which should trigger the wait_for()
condition for the zero()
method, self.last_printed > 0
.
Any idea why this program is not working as intended?