浅谈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中urllib模块用法实例详解
Nov 19 Python
ansible作为python模块库使用的方法实例
Jan 17 Python
关于Python中异常(Exception)的汇总
Jan 18 Python
在java中如何定义一个抽象属性示例详解
Aug 18 Python
python3下使用cv2.imwrite存储带有中文路径图片的方法
May 10 Python
python bmp转换为jpg 并删除原图的方法
Oct 25 Python
Python实现简易过滤删除数字的方法小结
Jan 09 Python
用 Python 制作地球仪的方法
Apr 24 Python
python库skimage给灰度图像染色的方法示例
Apr 27 Python
python进行参数传递的方法
May 12 Python
基于python实现matlab filter函数过程详解
Jun 08 Python
python中Matplotlib绘制直线的实例代码
Jul 04 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
怎么样可以把 phpinfo()屏蔽掉?
2006/11/24 PHP
PHP中的float类型使用说明
2010/07/27 PHP
php学习之 数组声明
2011/06/09 PHP
关于WordPress的SEO优化相关的一些PHP页面脚本技巧
2015/12/10 PHP
php 三元运算符实例详细介绍
2016/12/15 PHP
下载站控制介绍字数显示的脚本 显示全部 隐藏介绍等功能
2009/09/19 Javascript
在页面中js获取光标/鼠标的坐标及光标的像素坐标
2013/11/11 Javascript
js函数名与form表单元素同名冲突的问题
2014/03/07 Javascript
移动手机APP手指滑动切换图片特效附源码下载
2015/11/30 Javascript
Javascript技术栈中的四种依赖注入详解
2016/02/23 Javascript
javascript的 {} 语句块详解
2016/02/27 Javascript
jQuery鼠标事件总结
2016/10/13 Javascript
JavaScript中return用法示例
2016/11/29 Javascript
从vue源码解析Vue.set()和this.$set()
2018/08/30 Javascript
浅谈JavaScript 代码整洁之道
2018/10/23 Javascript
nodejs基础之常用工具模块util用法分析
2018/12/26 NodeJs
Vue源码之关于vm.$delete()/Vue.use()内部原理详解
2019/05/01 Javascript
gulp构建小程序的方法步骤
2019/05/31 Javascript
对Layer弹窗使用及返回数据接收的实例详解
2019/09/26 Javascript
[02:28]DOTA2英雄基础教程 狼人
2013/12/23 DOTA
2款Python内存检测工具介绍和使用方法
2014/06/01 Python
python中ConfigParse模块的用法
2014/09/29 Python
详解JavaScript编程中的window与window.screen对象
2015/10/26 Python
python实现字符串加密 生成唯一固定长度字符串
2019/03/22 Python
python实现美团订单推送到测试环境,提供便利操作示例
2019/08/09 Python
Python魔术方法专题
2020/06/19 Python
python实现mask矩阵示例(根据列表所给元素)
2020/07/30 Python
css实例教程 一款纯css3实现的超炫动画背画特效
2014/11/05 HTML / CSS
印尼最大的网上书店:Gramedia.com
2018/09/13 全球购物
哈曼俄罗斯官方网上商店:Harman.club
2020/07/24 全球购物
中国梦我的梦演讲稿
2014/04/23 职场文书
入党积极分子考察意见
2015/06/02 职场文书
超市店长竞聘书
2015/09/15 职场文书
漫画「请问您今天要来点兔子吗?」最新杂志彩页公开
2022/03/24 日漫
Vue OpenLayer测距功能的实现
2022/04/20 Vue.js
彻底弄懂Python中的回调函数(callback)
2022/06/25 Python