python threading之死锁和可重入锁
一、死锁
简单来说,死锁是一个资源被多次调用,而多次调用方都未能释放该资源就会造成死锁,这里结合例子说明下两种常见的死锁情况。
1、迭代死锁
该情况是一个线程“迭代”请求同一个资源,直接就会造成死锁:
1import threading
2import time
3class MyThread(threading.Thread):
4 def run(self):
5 global num
6 time.sleep(1)
7 if mutex.acquire(1):
8 num = num+1
9 msg = self.name+' set num to '+str(num)
10 print msg
11 mutex.acquire()
12 mutex.release()
13 mutex.release()
14num = 0
15mutex = threading.Lock()
16def test():
17 for i in range(5):
18 t = MyThread()
19 t.start()
20if __name__ == '__main__':
21 test()
上例中,在run函数的if判断中第一次请求资源,请求后还未 release ,再次acquire,最终无法释放,造成死锁。这里例子中通过将print下面的两行注释掉就可以正常执行了 ,除此之外也可以通过可重入锁解决,后面会提到。
2、互相调用死锁
上例中的死锁是在同一个def函数内多次调用造成的,另一种情况是两个函数中都会调用相同的资源,互相等待对方结束的情况。如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
1import threading
2import time
3class MyThread(threading.Thread):
4 def do1(self):
5 global resA, resB
6 if mutexA.acquire():
7 msg = self.name+' got resA'
8 print msg
9 if mutexB.acquire(1):
10 msg = self.name+' got resB'
11 print msg
12 mutexB.release()
13 mutexA.release()
14 def do2(self):
15 global resA, resB
16 if mutexB.acquire():
17 msg = self.name+' got resB'
18 print msg
19 if mutexA.acquire(1):
20 msg = self.name+' got resA'
21 print msg
22 mutexA.release()
23 mutexB.release()
24 def run(self):
25 self.do1()
26 self.do2()
27resA = 0
28resB = 0
29mutexA = threading.Lock()
30mutexB = threading.Lock()
31def test():
32 for i in range(5):
33 t = MyThread()
34 t.start()
35if __name__ == '__main__':
36 test()
这个死锁的示例稍微有点复杂。具体可以理下。
二、可重入锁
为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。这里以例1为例,如果使用RLock代替Lock,则不会发生死锁:
1import threading
2import time
3class MyThread(threading.Thread):
4 def run(self):
5 global num
6 time.sleep(1)
7 if mutex.acquire(1):
8 num = num+1
9 msg = self.name+' set num to '+str(num)
10 print msg
11 mutex.acquire()
12 mutex.release()
13 mutex.release()
14num = 0
15mutex = threading.RLock()
16def test():
17 for i in range(5):
18 t = MyThread()
19 t.start()
20if __name__ == '__main__':
21 test()
和例1不同之处在于threading.Lock()换成了threading.RLock() 。
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/python-rlock/4619.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.