死锁的原因及解决办法RLock递归锁
递归 解决办法 原因 死锁
2023-09-14 08:57:48 时间
死锁
说到死锁,可以讲一个科学家吃面的问题:
有几个科学家在一张桌子旁,桌子上只有一把筷子和一碗面,我们将面和筷子都加锁。这是可能会导致一个科学家抢到面,另一个科学家抢到筷子,这是就全部阻塞了,这就是死锁了。
如下代码:
from threading import Thread, Lock, RLock import time # 这个函数,先让拿筷子,再拿面条, def eat1(args, Chopsticks_lock, Noodles_lock): Chopsticks_lock.acquire() # 拿钥匙 print('%s拿到了筷子'%args) Noodles_lock.acquire() # 拿钥匙 print('%s拿到了面条'%args) print('%s吃到了面条'%args) Noodles_lock.release() # 还钥匙 Chopsticks_lock.release() # 还钥匙 # 这个函数,先让那面条,再让拿筷子。 def eat2(args, Chopsticks_lock, Noodles_lock): Noodles_lock.acquire() print('%s拿到了面条' % args) time.sleep(0.1) # 让睡0.1面,这样更容易,一个线程拿到面条,一个线程拿到筷子,出现阻塞,出现死锁。 Chopsticks_lock.acquire() print('%s拿到了筷子'%args) print('%s吃到了面条'%args) Noodles_lock.release() Chopsticks_lock.release() # 创建两个锁,分别给面条和筷子加锁。 Chopsticks_lock = Lock() Noodles_lock = Lock() Thread(target=eat1, args=('小明', Chopsticks_lock, Noodles_lock)).start() Thread(target=eat2, args=('小红', Chopsticks_lock, Noodles_lock)).start() Thread(target=eat1, args=('小兰', Chopsticks_lock, Noodles_lock)).start() Thread(target=eat2, args=('小军', Chopsticks_lock, Noodles_lock)).start()
打印结果:
小明拿到了筷子
小明拿到了面条
小明吃到了面条
小红拿到了面条
小兰拿到了筷子
看到小红拿到了面条,而小兰拿到了筷子,他们都需要对方拿到的资源来完成吃面条的整个过程,但是线程未使用完资源之前,不可被剥夺,并且线程拿不到需要的资源就会阻塞,就造成了死锁的情况。
如何解决?
引入递归锁。
递归锁RLock
from threading import Thread, Lock, RLock import time def eat1(args, Chopsticks_lock, Noodles_lock): Chopsticks_lock.acquire() print('%s拿到了筷子'%args) Noodles_lock.acquire() print('%s拿到了面条'%args) print('%s吃到了面条'%args) Noodles_lock.release() Chopsticks_lock.release() def eat2(args, Chopsticks_lock, Noodles_lock): Noodles_lock.acquire() print('%s拿到了面条' % args) time.sleep(0.1) Chopsticks_lock.acquire() print('%s拿到了筷子'%args) print('%s吃到了面条'%args) Noodles_lock.release() Chopsticks_lock.release() Chopsticks_lock = Noodles_lock = RLock() Thread(target=eat1, args=('小明', Chopsticks_lock, Noodles_lock)).start() Thread(target=eat2, args=('小红', Chopsticks_lock, Noodles_lock)).start() Thread(target=eat1, args=('小兰', Chopsticks_lock, Noodles_lock)).start() Thread(target=eat2, args=('小军', Chopsticks_lock, Noodles_lock)).start()
打印结果:
小明拿到了筷子
小明拿到了面条
小明吃到了面条
小红拿到了面条
小红拿到了筷子
小红吃到了面条
小兰拿到了筷子
小兰拿到了面条
小兰吃到了面条
小军拿到了面条
小军拿到了筷子
小军吃到了面条
值得注意的是,线程锁Lock是互斥锁,只有一把钥匙。而递归锁RLock是一个钥匙串的很多把钥匙,每个钥匙都可以开一把锁,但是只要一个进程拿到这串钥匙的其中一个钥匙,其他线程就拿不到钥匙了,这就是递归锁,就造成不了面条和筷子分别被两个线程拿到的情况了。
结束!
相关文章
- ECCV 2022 | 在视觉Transformer上进行递归,不增参数,计算量还少
- Python递归实现全排列
- filterTree递归树过滤实现
- 递归实现指数型,排列型,组合型枚举
- python 内置、匿名、高阶、递归等函数(3.1)
- xdoj递归数列_递归求数组元素之和
- Java递归详解_java难不难学
- 爱上「递归」之删除链表的倒数第 N 个结点
- 快速幂----递归
- SQL开发知识:MySql利用父id递归向下查询子节点的方法
- JAVA语言实现二叉树的层次遍历的非递归算法及递归算法详解编程语言
- 二叉树的深度 (递归与非递归方法整理)详解编程语言
- 查询MySQL递归查询:深入学习(mysql递归)
- MySQL实现递归子节点,让查询数据更方便(mysql递归子节点)
- 深入理解Linux下的rm命令的递归用法(linux rm 递归)
- 深入遍历二叉树的各种操作详解(非递归遍历)
- PHP实现数组递归转义的方法