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

死锁

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

# 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

此时进程已经死掉。

可重入锁

更简单的死锁情况是一个线程“迭代”请求同一个资源,直接就会造成死锁:

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,则不会发生死锁:

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

Posted in 未分类

发表评论