python死锁案例_11.python并发入门(part4 死锁与递归锁)

一、关于死锁。

死锁,就是当多个进程或者线程在执行的过程中,因争夺共享资源而造成的一种互相等待的现象,一旦产生了死锁,不加人工处理,程序会一直等待下去,这也被称为死锁进程。

下面是一个产生“死锁”现象的例子:

import threading

import time

lock_a = threading.Lock()

lock_b = threading.Lock()

class test_thread(threading.Thread):

def __init__(self):

super(test_thread,self).__init__()

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手里~双方都没有办法执行到后面的释放操作。

这也就相当于两个人要做交易,甲手里有苹果乙手里有菠萝,甲想吃乙手里的菠萝,乙想吃甲手里的苹果,但是谁都不愿意先把自己手里的东西先给对方~所以程序就会一直卡在这。

这就是死锁形成的原理。

二、递归锁。

解决死锁问题有一个特别有效的方法,就是递归锁.

递归锁与普通的互斥锁最大的不同就是,一个锁的对象内部,维护了一个计数器,这个计数器的初始值是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,能用递归锁尽量用递归锁!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值