1. 程式人生 > >python多執行緒程式設計(4): 死鎖和可重入鎖

python多執行緒程式設計(4): 死鎖和可重入鎖

線上程間共享多個資源的時候,如果兩個執行緒分別佔有一部分資源並且同時等待對方的資源,就會造成死鎖。儘管死鎖很少發生,但一旦發生就會造成應用的停止響應。下面看一個死鎖的例子:

複製程式碼
# encoding: UTF-8import 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