浅谈Python线程的同步互斥与死锁


Posted in Python onMarch 22, 2020

线程间通信方法

    1. 通信方法

线程间使用全局变量进行通信

    2. 共享资源争夺

共享资源:多个进程或者线程都可以操作的资源称为共享资源。对共享资源的操作代码段称为临界区。

影响 : 对共享资源的无序操作可能会带来数据的混乱,或者操作错误。此时往往需要同步互斥机制协调操作顺序。

    3. 同步互斥机制

同步 : 同步是一种协作关系,为完成操作,多进程或者线程间形成一种协调,按照必要的步骤有序执行操作。两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。

浅谈Python线程的同步互斥与死锁

互斥 : 互斥是一种制约关系,当一个进程或者线程占有资源时会进行加锁处理,此时其他进程线程就无法操作该资源,直到解锁后才能操作。一个公共资源同一时刻只能被一个进程或线程使用,多个进程或线程不能同时使用公共资源

浅谈Python线程的同步互斥与死锁

线程同步互斥方法

    线程Event同步

from threading import Event
e = Event() 创建线程event对象
e.wait([timeout]) 阻塞等待e被set
e.set() 设置e,使wait结束阻塞
e.clear() 使e回到未被设置状态
e.is_set() 查看当前e是否被设置

示例:

import time
import threading
 
event = threading.Event()
 
 
# 红绿灯
def lighter():
  count = 0
  event.set() # 刚进来的时候是绿灯
  while True:
    if 4 < count < 10:
      event.clear() # 清除设置,阻塞等待
      print("[信号灯]:红,不能通行", count)
    elif count >= 10: # 添加设置,继续执行
      event.set()
      count = 0
    else:
      event.set() # 添加设置,继续执行
      print("[信号灯]:绿灯,可以通行", count)
    time.sleep(1)
    count += 1
 
 
# 汽车
def car(name):
  while True:
    if event.is_set():
      print("{0}: 绿灯 , 走起...".format(name))
      time.sleep(1)
    else:
      print("{0}: 红灯 , 停车...".format(name))
      event.wait()
      print("{0}: 绿灯亮了 , 继续前进...".format(name))
 
 
light = threading.Thread(target=lighter, )
light.start()
car1 = threading.Thread(target=car, args=("小跑",))
car1.start()

    线程锁 Lock

from threading import Lock
lock = Lock() #创建锁对象
lock.acquire() #上锁 如果lock已经上锁再调用会阻塞
lock.release() #解锁

with lock: 上锁

with代码块结束自动解锁

示例:

from threading import Thread, Lock
from time import sleep
 
a = b = 0
lock = Lock()
 
 
# 子线程输出a b
def value():
  while True:
    lock.acquire() # 上锁
    if a != b:
      print("a = %d,b = %d" % (a, b))
    lock.release() # 解锁
 
 
t = Thread(target=value)
t.start()
 
# 主线程加锁更改a b时候,子线程处理a b 时也要进行加锁,重复加锁就会阻塞等待主线程处理结束
# 同理主进程再次更改a b 时等 子进程结束才可以
while True:
  with lock: # 自动上/解锁
    a += 1
    b += 1
t.join

死锁及其处理

    1. 定义

        死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。

    2. 死锁产生条件

        【互斥条件】:指线程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

       【请求和保持条件】:指线程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求线程阻塞,但又对自己已获得的其它资源保持不放。

        【不剥夺条件】:指线程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放,通常CPU内存资源是可以被系统强行调配剥夺的。

        【环路等待条件】:指在发生死锁时,必然存在一个线程——资源的环形链,即进程集合{T0,T1,T2,···,Tn}中的T0正在等待一个T1占用的资源;T1正在等待T2占用的资源,……,Tn正在等待已被T0占用的资源。

         简单来说造成死锁的原因可以概括成三句话:

【1】当前线程拥有其他线程需要的资源

【2】当前线程等待其他线程已拥有的资源

【3】都不放弃自己拥有的资源

浅谈Python线程的同步互斥与死锁

 T1拥有R1,T2拥有R2。T1请求使用R2,T2请求使用R1,但是T1,T2 都不愿释放R1,R2,互相一直等待下去,造成死锁

    3. 如何避免死锁

        死锁是我们非常不愿意看到的一种现象,我们要尽可能避免死锁的情况发生。通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或者几个,来预防发生死锁。预防死锁是一种较易实现的方法。但是由于所施加的限制条件往往太严格,可能会导致系统资源利用率。

from threading import Lock, Thread
 
 
# 交易类
class Account:
  def __init__(self, _id, balance, lock):
    self.id = _id
    self.balance = balance
    self.lock = lock # 各自账户锁
 
  # 取钱
  def withdraw(self, amount):
    self.balance -= amount
 
  # 存钱
  def deposit(self, amount):
    self.balance += amount
 
  # 查看账户
  def get_balance(self):
    return self.balance
 
 
# 转账
def transfer(from_, to, amount):
  if from_.lock.acquire(): # 锁住自己的账户
    from_.withdraw(amount) # 自己账户减少
    if to.lock.acquire(): # 锁住对方账户
      to.deposit(amount) # 对方账户增加
      to.lock.release() # 解锁对方账户
    from_.lock.release() # 自己账户解锁
  print("转账完成")
 
 
Abby = Account("Abby", 5000, Lock())
Balen = Account("Balen", 3000, Lock())
 
t = Thread(target=transfer, args=(Abby, Balen, 1000))
t2 = Thread(target=transfer, args=(Balen, Abby, 500))
t.start()
t2.start()
t.join()
t2.join()
 
print("Abby:", Abby.get_balance())
print("Balen:", Balen.get_balance())

到此这篇关于浅谈Python线程的同步互斥与死锁的文章就介绍到这了,更多相关Python线程同步互斥与死锁内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python捕捉和模拟鼠标事件的方法
Jun 03 Python
浅谈对yield的初步理解
May 29 Python
全面了解Nginx, WSGI, Flask之间的关系
Jan 09 Python
解决python线程卡死的问题
Feb 18 Python
python学习开发mock接口
Apr 28 Python
pandas 如何分割字符的实现方法
Jul 29 Python
python自动保存百度盘资源到百度盘中的实例代码
Aug 26 Python
Pytorch中Tensor与各种图像格式的相互转化详解
Dec 26 Python
tensorflow 2.1.0 安装与实战教程(CASIA FACE v5)
Jun 30 Python
如何利用python之wxpy模块玩转微信
Aug 17 Python
python 判断一组数据是否符合正态分布
Sep 23 Python
OpenCV 图像梯度的实现方法
Jul 25 Python
Django 项目布局方法(值得推荐)
Mar 22 #Python
python实现吃苹果小游戏
Mar 21 #Python
python实现贪吃蛇游戏源码
Mar 21 #Python
python实现微信打飞机游戏
Mar 24 #Python
Python类的动态绑定实现原理
Mar 21 #Python
Python类和实例的属性机制原理详解
Mar 21 #Python
Python生成器常见问题及解决方案
Mar 21 #Python
You might like
PHP基于Redis消息队列实现发布微博的方法
2017/05/03 PHP
扩展javascript的Date方法实现代码(prototype)
2010/11/20 Javascript
js解析与序列化json数据(三)json的解析探讨
2013/02/01 Javascript
js 火狐下取本地路径实现思路
2013/04/02 Javascript
浅析jQuery中调用ajax方法时在不同浏览器中遇到的问题
2014/06/11 Javascript
js获取微信版本号的方法
2015/05/12 Javascript
jQuery实现的fixedMenu下拉菜单效果代码
2015/08/24 Javascript
javascript性能优化之事件委托实例详解
2015/12/12 Javascript
AngularJS包括详解及示例代码
2016/08/17 Javascript
d3.js实现立体柱图的方法详解
2017/04/28 Javascript
JS 实现banner图片轮播效果(鼠标事件)
2017/08/04 Javascript
vue.js input框之间赋值方法
2018/08/24 Javascript
前后端常见的几种鉴权方式(小结)
2019/08/04 Javascript
使用layer弹窗,制作编辑User信息页面的方法
2019/09/27 Javascript
使用vscode快速建立vue模板过程详解
2019/10/10 Javascript
vue transition 在子组件中失效的解决
2019/11/12 Javascript
Vue + Node.js + MongoDB图片上传组件实现图片预览和删除功能详解
2020/04/29 Javascript
JavaScript Image对象实现原理实例解析
2020/08/26 Javascript
Python中的装饰器用法详解
2015/01/14 Python
scrapy自定义pipeline类实现将采集数据保存到mongodb的方法
2015/04/16 Python
pandas数据框,统计某列数据对应的个数方法
2018/04/11 Python
解决tensorflow测试模型时NotFoundError错误的问题
2018/07/26 Python
Python logging模块用法示例
2018/08/28 Python
Python爬虫实战之12306抢票开源
2019/01/24 Python
python UDP(udp)协议发送和接收的实例
2019/07/22 Python
python软件测试Jmeter性能测试JDBC Request(结合数据库)的使用详解
2021/01/26 Python
css3绘制天猫logo实现代码
2012/11/06 HTML / CSS
html5 input属性使用示例
2013/06/28 HTML / CSS
HTML5之消息通知的使用(Web Notification)
2018/10/30 HTML / CSS
会计岗位描述
2014/02/22 职场文书
药学职务聘任书
2014/03/29 职场文书
小学优秀教师先进事迹材料
2014/12/16 职场文书
导游词之湖北武当山
2019/09/23 职场文书
巧用 -webkit-box-reflect 倒影实现各类动效(小结)
2021/04/22 HTML / CSS
javascript函数式编程基础
2021/09/15 Javascript
mysql 索引的数据结构为什么要采用B+树
2022/04/26 MySQL