简单来说,死锁是一个资源被多次调用,而多次调用方都未能释放该资源就会造成死锁,这里结合例子说明下两种常见的死锁情况。
1、迭代死锁
该情况是一个线程“迭代”请求同一个资源,直接就会造成死锁:
123456789101112131415161718192021 | 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() |
上例中,在run函数的if判断中第一次请求资源,请求后还未 release ,再次acquire,最终无法释放,造成死锁。这里例子中通过将print下面的两行注释掉就可以正常执行了 ,除此之外也可以通过可重入锁解决,后面会提到。
2、互相调用死锁
上例中的死锁是在同一个def函数内多次调用造成的,另一种情况是两个函数中都会调用相同的资源,互相等待对方结束的情况。如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
123456789101112131415161718192021222324252627282930313233343536 | import 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() |
这个死锁的示例稍微有点复杂。具体可以理下。
二、可重入锁
为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。这里以例1为例,如果使用RLock代替Lock,则不会发生死锁:
1234567891011tax Highlighter v2.7.1.1 –>
上例中,在run函数的if判断中第一次请求资源,请求后还未 release ,再次acquire,最终无法释放,造成死锁。这里例子中通过将print下面的两行注释掉就可以正常执行了 ,除此之外也可以通过可重入锁解决,后面会提到。 2、互相调用死锁 上例中的死锁是在同一个def函数内多次调用造成的,另一种情况是两个函数中都会调用相同的资源,互相等待对方结束的情况。如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
这个死锁的示例稍微有点复杂。具体可以理下。 二、可重入锁 为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。这里以例1为例,如果使用RLock代替Lock,则不会发生死锁:
|