脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Python - Python Thread虚假唤醒概念与防范详解

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

2023-03-02 13:05狂飙-高启强-张颂文-王天 Python

这篇文章主要介绍了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虚假唤醒内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://wtl4it.blog.csdn.net/article/details/129213883

延伸 · 阅读

精彩推荐
  • Pythonpython基于selenium爬取斗鱼弹幕

    python基于selenium爬取斗鱼弹幕

    这篇文章主要介绍了python如何基于selenium爬取斗鱼弹幕,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下...

    Martina_oh4982021-09-07
  • PythonPython HTTP客户端自定义Cookie实现实例

    Python HTTP客户端自定义Cookie实现实例

    这篇文章主要介绍了Python HTTP客户端自定义Cookie实现实例的相关资料,需要的朋友可以参考下...

    academy4902020-10-05
  • Python如何用python实现一个HTTP连接池

    如何用python实现一个HTTP连接池

    这篇文章主要介绍了如何用python实现一个HTTP连接池的步骤,帮助大家更好的理解和使用python,感兴趣的朋友可以了解下...

    终末之冬10582021-08-25
  • Python利用Python操作MongoDB数据库的详细指南

    利用Python操作MongoDB数据库的详细指南

    MongoDB是由C++语言编写的非关系型数据库,是一个基于分布式文件存储的开源数据库系统,其内容存储形式类似JSON对象,下面这篇文章主要给大家介绍了关于利...

    运维开发故事12622022-06-24
  • Pythonpython实现zabbix发送短信脚本

    python实现zabbix发送短信脚本

    这篇文章主要为大家详细介绍了python实现zabbix发送短信脚本,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    秋雪夜雨寒7522021-04-02
  • Pythonpython如何调用php文件中的函数详解

    python如何调用php文件中的函数详解

    这篇文章主要给大家介绍了关于python如何调用php文件中函数的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价...

    xiaofeiyuan12322021-08-19
  • Python利用Python函数实现一个万历表完整示例

    利用Python函数实现一个万历表完整示例

    这篇文章主要给大家介绍了关于如何利用Python函数实现一个万历表的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考...

    做个不一样的小丑6442021-08-28
  • PythonPython根据过滤器拆分列表

    Python根据过滤器拆分列表

    这篇文章主要介绍了Python根据过滤器拆分列表,利用Python代码实现代通过过滤器拆分列表的功能。文章围绕其相关资料展开详细内容,需要的朋友可以参考一...

    Felix9712022-02-28