[TOC]
**多进程好多线程都有死锁的问题**
## 一 死锁现象
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,
### 死锁案例-科学家吃面问题
~~~
import time
from threading import Thread,Lock
def eat1(name,fork_lock,noodle_lock):
fork_lock.acquire() #拿叉子锁
print('%s拿到叉子了'%name)
noodle_lock.acquire() #拿面条锁
print('%s拿到面条了' % name)
print('%s吃面'%name)
noodle_lock.release() #释放面条锁
fork_lock.release() #释放叉子锁
def eat2(name,fork_lock,noodle_lock):
noodle_lock.acquire()
print('%s拿到面条了' % name)
time.sleep(1)
fork_lock.acquire()
print('%s拿到叉子了' % name)
print('%s吃面'%name)
fork_lock.release()
noodle_lock.release()
fork_lock = Lock()
noodle_lock = Lock()
Thread(target=eat1,args=('alex',fork_lock,noodle_lock)).start()
Thread(target=eat2,args=('wusir',fork_lock,noodle_lock)).start()
~~~
**执行效果**
~~~
alex拿到叉子了
alex拿到面条了
alex吃面
wusir拿到面条了
yuan拿到叉子了 #出现死锁,整个程序阻塞住
~~~
## 二 递归锁
解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。
### 递归锁解决吃面问题
~~~
import time
from threading import Thread,RLock
def eat1(name,fork_lock,noodle_lock):
fork_lock.acquire()
print('%s拿到叉子了'%name)
noodle_lock.acquire()
print('%s拿到面条了' % name)
print('%s吃面'%name)
noodle_lock.release()
fork_lock.release()
def eat2(name,fork_lock,noodle_lock):
noodle_lock.acquire()
print('%s拿到面条了' % name)
time.sleep(1)
fork_lock.acquire()
print('%s拿到叉子了' % name)
print('%s吃面'%name)
fork_lock.release()
noodle_lock.release()
fork_lock =noodle_lock = RLock()
#一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,
#这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止
Thread(target=eat1,args=('alex',fork_lock,noodle_lock)).start()
Thread(target=eat2,args=('wusir',fork_lock,noodle_lock)).start()
Thread(target=eat1,args=('yuan',fork_lock,noodle_lock)).start()
~~~
执行结果:
```
alex拿到叉子了
alex拿到面条了
alex吃面
wusir拿到面条了
wusir拿到叉子了
wusir吃面
yuan拿到叉子了
yuan拿到面条了
yuan吃面
Process finished with exit code 0
```
## 互斥锁和递归锁的区别
互斥锁在同一个线程中连续acquire一次以上就会死锁
递归锁在同一个线程中可以连续的acquire多次而不发生死锁
* 普遍说法 :
递归锁可以代替互斥锁来解决死锁现象
* 实际上 :
递归锁的解决死锁实际上是牺牲了时间和空间的
**死锁从本质上来讲是一种逻辑错**
**递归锁没有从根本上解决死锁问题**
- 基础部分
- 基础知识
- 变量
- 数据类型
- 数字与布尔详解
- 列表详解list
- 字符串详解str
- 元组详解tup
- 字典详解dict
- 集合详解set
- 运算符
- 流程控制与循环
- 字符编码
- 编的小程序
- 三级菜单
- 斐波那契数列
- 汉诺塔
- 文件操作
- 函数相关
- 函数基础知识
- 函数进阶知识
- lambda与map-filter-reduce
- 装饰器知识
- 生成器和迭代器
- 琢磨的小技巧
- 通过operator函数将字符串转换回运算符
- 目录规范
- 异常处理
- 常用模块
- 模块和包相关概念
- 绝对导入&相对导入
- pip使用第三方源
- time&datetime模块
- random随机数模块
- os 系统交互模块
- sys系统模块
- shutil复制&打包模块
- json&pickle&shelve模块
- xml序列化模块
- configparser配置模块
- hashlib哈希模块
- subprocess命令模块
- 日志logging模块基础
- 日志logging模块进阶
- 日志重复输出问题
- re正则表达式模块
- struct字节处理模块
- abc抽象类与多态模块
- requests与urllib网络访问模块
- 参数控制模块1-optparse-过时
- 参数控制模块2-argparse
- pymysql数据库模块
- requests网络请求模块
- 面向对象
- 面向对象相关概念
- 类与对象基础操作
- 继承-派生和组合
- 抽象类与接口
- 多态与鸭子类型
- 封装-隐藏与扩展性
- 绑定方法与非绑定方法
- 反射-字符串映射属性
- 类相关内置方法
- 元类自定义及单例模式
- 面向对象的软件开发
- 网络-并发编程
- 网络编程SOCKET
- socket简介和入门
- socket代码实例
- 粘包及粘包解决办法
- 基于UDP协议的socket
- 文件传输程序实战
- socketserver并发模块
- 多进程multiprocessing模块
- 进程理论知识
- 多进程与守护进程
- 锁-信号量-事件
- 队列与生产消费模型
- 进程池Pool
- 多线程threading模块
- 进程理论和GIL锁
- 死锁与递归锁
- 多线程与守护线程
- 定时器-条件-队列
- 线程池与进程池(新方法)
- 协程与IO模型
- 协程理论知识
- gevent与greenlet模块
- 5种网络IO模型
- 非阻塞与多路复用IO实现
- 带着目标学python
- Pycharm基本使用
- 爬虫
- 案例-爬mzitu美女
- 案例-爬小说
- beautifulsoup解析模块
- etree中的xpath解析模块
- 反爬对抗-普通验证码
- 反爬对抗-session登录
- 反爬对抗-代理池
- 爬虫技巧-线程池
- 爬虫对抗-图片懒加载
- selenium浏览器模拟