本文作者:云初冀北

Python Thread虚假唤醒概念与防范详解

Python Thread虚假唤醒概念与防范详解摘要: 什么是虚假唤醒虚假唤醒是一种现象,它只会出现在多线程环境中,指的是在多线程环境下,多个线程等待在同一个条件上,等到条件满足时,所有等待的线程都被唤醒,但由于多个线程执行的顺序不同,...

?=什么是虚假唤醒

虚假唤醒是一种现象,它只会出现在多线程环境中,指的是在多线程环境下,多个线程等待在同一个条件上,等到条件满足时,所有等待的线程都被唤醒,但由于多个线程执的顺序不同,后面竞争到锁的线程在获得时间片时条件已经不再满足,线程应该继续睡眠但是却继续往下运行的一种现象。

上面是比较书面化的定义,我们用人能听懂的话来介绍一下虚假唤醒。

多线程环境的编程中,我们经常遇到让多个线程等待在一个条件上,等到这个条件成立的时候我们再去唤醒这些线程,让它们接着往下执行代码的场景。假如某一时刻条件成立,所有的线程都被唤醒了,然后去竞争锁,因为同一时刻只会有一个线程能拿到锁,其他的线程都会阻塞到锁上无法往下执行,等到成功争抢到锁的线程消费完条件,释放了锁,后面的线程继续运行,拿到锁时这个条件很可能已经不满足了,这个时候线程应该继续在这个条件上阻塞下去,而不应该继续执行,如果继续执行了,就说发生了虚假唤醒。

import Threading from threaDIng imPort ConditiON class Data: def __init__(self, cond, num): self.num = num self.cond = cond def add(self): self.cond: Condition = self.cond self.cond.acqUIre() if self.num > 0: self.cond.wait() self.num += 1 print(threading.current_thread().GetName(), self.num) self.cond.notifyAll() self.cond.release() def decr(self): self.cond: Condition = self.cond self.cond.acquire() if self.num == 0: self.cond.wait() self.num -= 1 print(threading.current_thread().getName(), self.num) self.cond.notifyAll() self.cond.release() if __name__ == '__main__': cond = Condition() num = 0 data = Data(cond, 0) thread_add = threading.Thread(name="A", target=data.add) thread_decr = threading.Thread(name="B", target=data.decr) thread_add.start() thread_decr.start()  

Python Thread虚假唤醒概念与防范详解

现在改用4个线程

import threading from threading import Condition class Data: def __init__(self, cond, num): self.num = num self.cond = cond def add(self): self.cond: Condition = self.cond self.cond.acquire() if self.num > 0: self.cond.wait() self.num += 1 print(threading.current_thread().getName(), self.num) self.cond.notifyAll() self.cond.release() def decr(self): self.cond: Condition = self.cond self.cond.acquire() if self.num == 0: self.cond.wait() self.num -= 1 print(threading.current_thread().getName(), self.num) self.cond.notifyAll() self.cond.release() if __name__ == '__main__': cond = Condition() num = 0 data = Data(cond, 0) thread_add = threading.Thread(name="A", target=data.add) thread_decr = threading.Thread(name="B", target=data.decr) thread_add2 = threading.Thread(name="C", target=data.add) thread_decr2 = threading.Thread(name="D", target=data.decr) thread_add.start() thread_decr.start() thread_add2.start() thread_decr2.start()

Python Thread虚假唤醒概念与防范详解

还没有出现问题!!!

使用20个线程同时跑

import threading from threading import Condition class Data: def __init__(self, cond, num): self.num = num self.cond = cond def add(self): self.cond: Condition = self.cond self.cond.acquire() if self.num > 0: self.cond.wait() self.num += 1 print(threading.current_thread().getName(), self.num) self.cond.notifyAll() self.cond.release() def decr(self): self.cond: Condition = self.cond self.cond.acquire() if self.num == 0: self.cond.wait() self.num -= 1 print(threading.current_thread().getName(), self.num) self.cond.notifyAll() self.cond.release() if __name__ == '__main__': cond = Condition() num = 0 data = Data(cond, 0) for i in range(10): thread_add = threading.Thread(name="A", target=data.add) thread_add.start() for i in range(10): thread_decr = threading.Thread(name="B", target=data.decr) thread_decr.start()

Python Thread虚假唤醒概念与防范详解

这时就出现了问题!!!

现在改用while进行判断

防止虚假唤醒:

import threading from threading import Condition class Data: def __init__(self, cond, num): self.num = num self.cond = cond def add(self): self.cond: Condition = self.cond self.cond.acquire() # 这里采用了while进行判断,防止虚假唤醒 while self.num > 0: self.cond.wait() self.num += 1 print(threading.current_thread().getName(), self.num) self.cond.notifyAll() self.cond.release() def decr(self): self.cond: Condition = self.cond self.cond.acquire() # 这里采用了while进行判断,防止虚假唤醒 while self.num == 0: self.cond.wait() self.num -= 1 print(threading.current_thread().getName(), self.num) self.cond.notifyAll() self.cond.release() if __name__ == '__main__': cond = Condition() num = 0 data = Data(cond, 0) for i in range(10): thread_add = threading.Thread(name="A", target=data.add) thread_add.start() for i in range(10): thread_decr = threading.Thread(name="B", target=data.decr) thread_decr.start()

Python Thread虚假唤醒概念与防范详解

这个例子与上面的代码几乎没有差别,只是把if判断换成了while判断,所以每次萧炎和唐三醒过来之后都会再判断一下有没有苹果(唤醒自己的条件是否满足),如果不满足,就会继续睡下去,不会接着往下运行,从而避免了虚假唤醒。

总结

等待在一个条件上的线程被全部唤醒后会去竞争锁,所以这些线程会一个一个地去消费这个条件,等到后面的线程去消费这个条件时,条件可能已经不满足了,所以每个被唤醒的线程都需要再检查一次条件是否满足。如果不满足,应该继续睡下去;只有满足了才能往下执行。

到此这篇关于Python Thread虚假唤醒概念与防范详解的文章就介绍到这了,更多相关python Thread虚假唤醒内容请搜索云初冀北以前的文章或继续浏览下面的相关文章希望大家以后多多支持云初冀北!

免责声明
本站提供的资源,都来自网络,版权争议与本站无关,所有内容及软件的文章仅限用于学习和研究目的。不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,我们不保证内容的长久可用性,通过使用本站内容随之而来的风险与本站无关,您必须在下载后的24个小时之内,从您的电脑/手机中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。侵删请致信E-mail:Goliszhou@gmail.com
$

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

阅读
分享

发表评论

快捷回复:

评论列表 (暂无评论,207人围观)参与讨论

还没有评论,来说两句吧...