Python线程.条件.通知全部()不触发下一个线程

2024-04-24 10:41:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试解决LeetCode问题,Print Zero Even Odd

enter image description hereenter image description here

我使用^{}对象尝试了以下解决方案:

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()

但是,当我运行这个时,我发现它打印0,然后1,然后无限期挂起:

^{pr2}$

我有点困惑,为什么在第一次调用odd()之后,zero()就不再被调用了。毕竟,在打印odd()中的1之后,self.last_printed被设置为1,这应该触发zero()方法的wait_for()条件。在

你知道为什么这个程序不能正常工作吗?在


Tags: andselfnoneifdefnotifyconditionint
1条回答
网友
1楼 · 发布于 2024-04-24 10:41:18

正如Sraw指出的,我的代码中没有循环,因此没有理由期望再次调用zero()。最后,我使用threading.Lock对象以不同的方式解决了这个问题:

import threading
from typing import Callable, Optional


class ZeroEvenOdd:
    def __init__(self, n: int):
        self.n = n
        self.i = 0

        self.lock_zero = threading.Lock()
        self.lock_odd = threading.Lock()
        self.lock_even = threading.Lock()

        self.lock_odd.acquire()
        self.lock_even.acquire()

    def zero(self, printNumber: Callable[[int], None]) -> None:
        for _ in range(self.n):
            self.lock_zero.acquire()
            printNumber(0)

            if self.i % 2 == 0:
                self.lock_odd.release()
            else:
                self.lock_even.release()

    def even(self, printNumber: Callable[[int], None]) -> None:
        for i in range(2, self.n + 1, 2):
            self.lock_even.acquire()
            printNumber(i)
            self.i = i
            self.lock_zero.release()

    def odd(self, printNumber: Callable[[int], None]) -> None:
        for i in range(1, self.n + 1, 2):
            self.lock_odd.acquire()
            printNumber(i)
            self.i = i
            self.lock_zero.release()


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()

这将打印所需的输出:

^{pr2}$

并以相当快且节省内存的方式解决LeetCode问题:

enter image description here

相关问题 更多 >