【问题标题】:Why isn't my thread starting back up when the Condition object is notified/released?为什么通知/释放 Condition 对象时我的线程没有启动备份?
【发布时间】:2020-09-01 19:53:27
【问题描述】:

这个问题与 Python 3.6 有关。

我有一段代码运行线程库中的一个线程,以及程序的主线程。两个线程都访问一个不是线程安全的对象,所以我让它们在使用对象之前锁定Condition 对象。我生成的线程只需要每 5 分钟访问/更新一次该对象,因此循环中有一个 5 分钟的睡眠计时器。

目前,主线程永远不会获得锁。当第二个线程释放Condition 并开始等待sleep() 调用时,主线程永远不会唤醒/获取锁。就好像主线程已经死了一样。

class Loader:
    def __init__(self, q):
        ...
        self.queryLock = threading.Condition()
        ...
        thread = Thread(target=self.threadfunc, daemon=True)
        thread.start()
        ...
        self.run()

    def threadfunc(self):
        ...
        while True:
            self.queryLock.acquire()
            [critical section #1]
            self.queryLock.notify()
            self.queryLock.release()
            sleep(300)

    def run(self):
        ...
        while True:
            ...
            self.queryLock.acquire()
            [critical section #2]
            self.queryLock.notify()
            self.queryLock.release()
            ...

【问题讨论】:

  • 一个可能的问题是您使用了一个基本锁就足够的条件。根据文档,如果您在初始化 Condition 时不提供任何参数,它会创建一个底层 RLock(可重入锁)来使用,而您真正需要的是一个基本锁。尝试将 Condition 初始化为 Condition(lock=Lock()) 或将其替换为 Lock
  • 你能确认没有线程等待条件吗?另外,你能告诉我们主线程的真实代码吗?使用...,我无法判断主线程大部分时间实际上在做什么。另外,在[critical section #2] 代码期间会发生什么?线程在持有锁时正在做什么很重要。你是说 没有 线程获得锁吗?或者你是说一个线程一遍又一遍地获得锁而另一个没有机会?

标签: python multithreading thread-safety python-3.6


【解决方案1】:

我相信你真的不需要使用条件。看起来一个简单的Lock 可以完成您的工作。您实际上并没有验证是否满足某些条件,也没有使用 Condition 的特殊方法wait()


话虽如此,关于您提供的代码,您的主线程似乎太“快”了,并且在其他线程有机会之前重新获取了锁。 这是您的代码稍作修改的版本,其中主线程稍等片刻,给另一个线程一个机会,它成功获取锁并继续。

class Loader:
    def __init__(self):
        self.queryLock = threading.Condition()
        thread = Thread(target=self.threadfunc, daemon=True)
        thread.start()
        self.run()
    
    def threadfunc(self):
        while True:
            self.queryLock.acquire()
            print("critical section 1")
            time.sleep(1)
            self.queryLock.notify()
            self.queryLock.release()
            time.sleep(5)
    
    def run(self):
        while True:
            self.queryLock.acquire()
            print("critical section 2")
            time.sleep(2)
            self.queryLock.notify()
            self.queryLock.release()
            print("main is waiting a bit")
            time.sleep(1)


Loader()

比赛条件很有趣:)

【讨论】:

  • Re,“……你的主线程太‘快’了”,有一个名字; “饥饿。”当锁定和/或信号模式设法使一个(或多个)线程总是晚饭时,这就是我们所说的。这个例子中的主线程是starving这个新线程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-25
  • 2021-10-14
  • 2015-06-14
相关资源
最近更新 更多