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

来源:互联网 发布:php base64_encoder 编辑:程序博客网 时间:2024/06/10 12:07

原文转载自:http://www.cnblogs.com/holbrook/archive/2012/03/08/2385449.html

死锁

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

复制代码
# encoding: UTF-8import threadingimport timeclass 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 = 0resB = 0mutexA = 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

此时进程已经死掉。==== 》原因在于,Thread-5 需要资源resA变量,而Thread-4需要资源resB变量。导致的死锁。

可重入锁

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

复制代码
import threadingimport timeclass 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 = 0mutex = 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 threadingimport timeclass 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 = 0mutex = 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

0 0
原创粉丝点击