python多线程编程4: 死锁和可重入锁

在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。尽管死锁很少发生,但一旦发生就会造成应用的停止响应。下面看一个死锁的例子:

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 iin 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 iin 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 iin 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
喜欢就支持一下吧
点赞11 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容