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?


 
    