在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。尽管死锁很少发生,但一旦发生就会造成应用的停止响应。下面看一个死锁的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
# encoding: UTF-8 import threading import time class MyThread(threading.Thread): def do1( self ): global resA, resB if mutexA.acquire(): msg = self .name + ' got resA' print msg if mutexB.acquire( 1 ): msg = self .name + ' got resB' print msg mutexB.release() mutexA.release() def do2( self ): global resA, resB if mutexB.acquire(): msg = self .name + ' got resB' print msg if mutexA.acquire( 1 ): msg = self .name + ' got resA' print msg mutexA.release() mutexB.release() def run( self ): self .do1() self .do2() resA = 0 resB = 0 mutexA = threading.Lock() mutexB = threading.Lock() def test(): for i in range ( 5 ): t = MyThread() t.start() if __name__ = = '__main__' : test() |
执行结果:
Thread-1 got resA
Thread-1 got resB
Thread-1 got resB
Thread-1 got resA
Thread-2 got resA
Thread-2 got resB
Thread-2 got resB
Thread-2 got resA
Thread-3 got resA
Thread-3 got resB
Thread-3 got resB
Thread-3 got resA
Thread-5 got resA
Thread-5 got resB
Thread-5 got resB
Thread-4 got resA
此时进程已经死掉。
可重入锁
更简单的死锁情况是一个线程“迭代”请求同一个资源,直接就会造成死锁:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import threading import time class MyThread(threading.Thread): def run( self ): global num time.sleep( 1 ) if mutex.acquire( 1 ): num = num + 1 msg = self .name + ' set num to ' + str (num) print msg mutex.acquire() mutex.release() mutex.release() num = 0 mutex = threading.Lock() def test(): for i in range ( 5 ): t = MyThread() t.start() if __name__ = = '__main__' : test() |
为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import threading import time class MyThread(threading.Thread): def run( self ): global num time.sleep( 1 ) if mutex.acquire( 1 ): num = num + 1 msg = self .name + ' set num to ' + str (num) print msg mutex.acquire() mutex.release() mutex.release() num = 0 mutex = threading.RLock() def test(): for i in range ( 5 ): t = MyThread() t.start() if __name__ = = '__main__' : test() |
执行结果:
Thread-1 set num to 1
Thread-3 set num to 2
Thread-2 set num to 3
Thread-5 set num to 4
Thread-4 set num to 5
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容