线程死锁和递归锁
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。
死锁示例
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2018/4/14 11:07
# @Author : CaiChangEn
# @Email : [email protected]
# @Software: PyCharm
import threading,time
import time
class MyThread(threading.Thread):
def actionA(self):
A.acquire() # A获得锁
print(self.name,'GotA',time.ctime())
time.sleep(2)
B.acquire() # B获得锁
print(self.name, 'GotB', time.ctime())
time.sleep(1)
B.release() # 释放锁
A.release() # 释放锁
def actionB(self):
B.acquire() # B获得锁
print(self.name,'GotB',time.ctime())
time.sleep(2)
A.acquire() # A获得锁
print(self.name, 'GotA', time.ctime())
time.sleep(1)
A.release() # 释放锁
B.release() # 释放锁
def run(self):
self.actionA()
self.actionB()
if __name__ == '__main__':
# 创建两把锁
A=threading.Lock()
B=threading.Lock()
L=[]
for i in range(5):
t=MyThread()
t.start()
L.append(t)
for i in L:
i.join() # 主线程等待子线程结束之后再执行
print('ending...')
分析
当第一个线程进来的时候首先会进入到actionA获得A和B的锁,然后释放释放之后会有第二个线程启动,那么在线程启动的同时第一个线程会进入到actionB获得B的锁,那么此时的第二个线程会进入到actionA获得A的锁,进入到此时,问题就来了,第一个线程需要获得B锁,第二个线程火会需要获得A锁,那么此时就产生的锁竞争,继而引发死锁的产生
解决死锁的递归锁
解决方法,递归所,在Python中为了支持统一线程中多次请求同一资源,python提供了可重入锁RLock
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require,直到一个线程所有的acquire都被release,其他的线程才能获得资源;
二者的区别:递归锁可以连续acquire多次,互斥锁只能acquire一次
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2018/4/14 11:07
# @Author : CaiChangEn
# @Email : [email protected]
# @Software: PyCharm
import threading,time
import time
class MyThread(threading.Thread):
def actionA(self):
r_lock.acquire() # A获得锁
print(self.name,'GotA',time.ctime())
time.sleep(2)
r_lock.acquire() # B获得锁
print(self.name, 'GotB', time.ctime())
time.sleep(1)
r_lock.release() # 释放锁
r_lock.release() # 释放锁
def actionB(self):
r_lock.acquire() # B获得锁
print(self.name,'GotB',time.ctime())
time.sleep(2)
r_lock.acquire() # A获得锁
print(self.name, 'GotA', time.ctime())
time.sleep(1)
r_lock.release() # 释放锁
r_lock.release() # 释放锁
def run(self):
self.actionA()
self.actionB()
if __name__ == '__main__':
# 创建两把锁
# A=threading.Lock()
# B=threading.Lock()
r_lock=threading.RLock() # 创建递归锁
L=[]
for i in range(5):
t=MyThread()
t.start()
L.append(t)
for i in L:
i.join() # 主线程等待子线程结束之后再执行
print('ending...')
分析
rlock是递归锁,拿我们现在这个例子来说,它们其实用的都是一把锁,就是在内部加了一个计数器,我们上面的例子获得了2把锁,那么此时的计数器应该大于0,当第一个线程进来的时候,会直接获得两把锁,执行完成actionA会释放两把锁,那么第一个线程此时就会进入到actionB那么这个过程中会启动第二个线程(主要看切换时间够不够),第二个线程又会执行actionA,那么此时第一个线程是等待的,因为递归锁的原理就是不管有多少个线程不管有多少个锁,如果一个人获得了锁,就声明了其他人也不可以获得其他的锁 ;
- 注意: 一个线程内部可以维护多个锁,只要第一个线程获得一把锁,那就意味着其他线程是进不来的,在这么一个时刻只有一个线程能够被执行,其他线程一直是等待锁释放的状态,这就保证了这把锁,一直是一个锁在使用
閱讀更多 動漫資深愛好者和IT 的文章