1、关于死锁。python
死锁,就是当多个进程或者线程在执行的过程当中,因争夺共享资源而形成的一种互相等待的现象,一旦产生了死锁,不加人工处理,程序会一直等待下去,这也被称为死锁进程。ide
下面是一个产生“死锁”现象的例子:ui
import threading线程
import time对象
lock_a = threading.Lock()递归
lock_b = threading.Lock()进程
class test_thread(threading.Thread):资源
def __init__(self):get
super(test_thread,self).__init__()it
def run(self):
self.fun1()
self.fun2()
def fun1(self):
lock_a.acquire()
print "I am %s , get res: %s---%s" %(self.name, "ResA",time.time())
lock_b.acquire()
print "I am %s , get res: %s---%s" %(self.name, "ResB",time.time())
lock_b.release()
lock_a.release()
def fun2(self):
lock_b.acquire()
print ("I am %s , get res: %s---%s" %(self.name, "ResB",time.time()))
time.sleep(0.2)
lock_a.acquire()
print ("I am %s , get res: %s---%s" %(self.name, "ResA",time.time()))
lock_a.release()
lock_b.release()
if __name__ == "__main__":
print "start---------------------------%s"%(time.time())
for i in range(0, 10):
my_thread = test_thread()
my_thread.start()
输出执行结果:
start---------------------------1494682814.1
I am Thread-1 , get res: ResA---1494682814.1
I am Thread-1 , get res: ResB---1494682814.1
I am Thread-1 , get res: ResB---1494682814.1
I am Thread-2 , get res: ResA---1494682814.1
下面来分析代码,为何会产生死锁:
开了10个线程,首先确定会有一个线程去拿到lock_a这把锁,其他的线程只能阻塞,一直等到lock_a这把锁被释放,而后这个线程又得到了一把锁就是lock_b,执行完了一条print操做后,释放lock_b这把锁,此时,其余的线程仍是没有办法去执行func1里面的资源,释放了lock_b这把锁后,紧接着lock_a也被释放了,此时,下一个线程就能够去执行func1中的资源了,接下来,线程1执行到了func2拿到了lock_b这把锁,而后执行一个print输出,I am Thread-1 , get res: ResB---1494682814.1,sleep0.2秒,在第一个线程sleep的过程当中第二个线程开始执行,第二个线程在执行func1的时候,首先拿到了lock_a这把锁,执行了下面的print语句,I am Thread-2 , get res: ResA---1494682814.1,此时的状况就是线程1拿到了lock_b这把锁,线程2拿到了lock_a这把锁,那么问题来了,线程2若是想继续执行func1后面的内容,须要去得到lock_b这把锁,而此时lock_b锁已经被线程1拿走了(线程1执行到了func2拿走了lock_b锁,而且还没被释放~),线程1,sleep0.2秒后,须要继续执行func2中的内容,此时,须要拿到lock_a锁,(lock_a锁,被线程2执行func1的时候拿走了,而且没有被释放~),如今的状况就是线程1须要lock_a锁,可是lock_a在线程2手里,线程2须要lock_b锁,可是lock_b锁在线程1手里~双方都没有办法执行到后面的释放操做。
这也就至关于两我的要作交易,甲手里有苹果乙手里有菠萝,甲想吃乙手里的菠萝,乙想吃甲手里的苹果,可是谁都不肯意先把本身手里的东西先给对方~因此程序就会一直卡在这。
这就是死锁造成的原理。
2、递归锁。
解决死锁问题有一个特别有效的方法,就是递归锁.
递归锁与普通的互斥锁最大的不一样就是,一个锁的对象内部,维护了一个计数器,这个计数器的初始值是0,当一个线程acquire一次这个锁时,内部计数器+1,可是,这把锁的计数器一旦大于0,其余的线程是没法拿到这把锁的,只有当前线程能够拿。
(当前线程acquire一次,计数器+1,release一次计数器-1,因此,当前的线程想要完全释放掉递归锁,acquire多少次,就要release多少次!!!)
(这个计数器,就是递归锁中的count。)
还拿刚才的那段产生死锁的代码来举例:
import threading
import time
r_lock = threading.RLock() #RLock是用来产生递归锁的一个类,产生一个递归锁。
class test_thread(threading.Thread):
def __init__(self):
super(test_thread,self).__init__()
def run(self):
self.fun1()
self.fun2()
def fun1(self):
r_lock.acquire() #count+1
print "I am %s , get res: %s---%s" %(self.name, "ResA",time.time())
r_lock.acquire() #count再+1
print "I am %s , get res: %s---%s" %(self.name, "ResB",time.time())
r_lock.release() #count -1
r_lock.release() #count 再-1
def fun2(self):
r_lock.acquire()
print ("I am %s , get res: %s---%s" %(self.name, "ResB",time.time()))
time.sleep(0.2)
r_lock.acquire()
print ("I am %s , get res: %s---%s" %(self.name, "ResA",time.time()))
r_lock.release()
r_lock.release()
if __name__ == "__main__":
print "start---------------------------%s"%(time.time())
r_lock = threading.RLock()
for i in range(0, 10):
my_thread = test_thread()
my_thread.start()
输出结果:
start---------------------------1494687542.43
I am Thread-1 , get res: ResA---1494687542.43
I am Thread-1 , get res: ResB---1494687542.43
I am Thread-1 , get res: ResB---1494687542.43
I am Thread-1 , get res: ResA---1494687542.63
I am Thread-2 , get res: ResA---1494687542.63
I am Thread-2 , get res: ResB---1494687542.63
I am Thread-2 , get res: ResB---1494687542.63
I am Thread-2 , get res: ResA---1494687542.83
I am Thread-4 , get res: ResA---1494687542.83
I am Thread-4 , get res: ResB---1494687542.83
I am Thread-4 , get res: ResB---1494687542.83
I am Thread-4 , get res: ResA---1494687543.04
I am Thread-6 , get res: ResA---1494687543.04
I am Thread-6 , get res: ResB---1494687543.04
I am Thread-6 , get res: ResB---1494687543.04
I am Thread-6 , get res: ResA---1494687543.24
I am Thread-8 , get res: ResA---1494687543.24
I am Thread-8 , get res: ResB---1494687543.24
I am Thread-8 , get res: ResB---1494687543.24
I am Thread-8 , get res: ResA---1494687543.44
I am Thread-10 , get res: ResA---1494687543.44
I am Thread-10 , get res: ResB---1494687543.44
I am Thread-10 , get res: ResB---1494687543.44
I am Thread-10 , get res: ResA---1494687543.65
I am Thread-5 , get res: ResA---1494687543.65
I am Thread-5 , get res: ResB---1494687543.65
I am Thread-5 , get res: ResB---1494687543.65
I am Thread-5 , get res: ResA---1494687543.85
I am Thread-9 , get res: ResA---1494687543.85
I am Thread-9 , get res: ResB---1494687543.85
I am Thread-9 , get res: ResB---1494687543.85
I am Thread-9 , get res: ResA---1494687544.06
I am Thread-7 , get res: ResA---1494687544.06
I am Thread-7 , get res: ResB---1494687544.06
I am Thread-7 , get res: ResB---1494687544.06
I am Thread-7 , get res: ResA---1494687544.26
I am Thread-3 , get res: ResA---1494687544.26
I am Thread-3 , get res: ResB---1494687544.26
I am Thread-3 , get res: ResB---1494687544.26
I am Thread-3 , get res: ResA---1494687544.46
从上面的例子来看,死锁的问题被完美的解决掉了。
最后,总结下递归锁:
在python中,若是同一个线程须要屡次去访问同一个共享资源,这个时候,就可使用递归锁(RLock),递归锁的内部,维护了一个Lock对象和一个counter计数变量,counter记录了acquire的次数,从而使得资源能够被屡次require。直到一个线程全部的acquire都被release,其余的线程才能得到资源。
因此说RLock能够彻底代替Lock,能用递归锁尽可能用递归锁!