Python 多執行緒死鎖的示例

2021-10-06 07:48:17 字數 4956 閱讀 7505

在 python 中多執行緒中為了防止資源競爭而出現問題,提供了鎖的機制,當乙個執行緒操作資源時進行加鎖,操作完畢後釋放鎖,這樣其他執行緒就不會同時操作資源匯出出現異常。

在 python 多執行緒中注意是兩種鎖:互斥鎖和遞迴鎖

那麼它們有什麼區別呢?

互斥鎖:

一旦乙個執行緒獲得乙個互斥鎖,會阻塞隨後嘗試獲得鎖的執行緒,直到它被釋放;任何執行緒都可以釋放它。

遞迴鎖:

遞迴鎖必須由獲取它的執行緒釋放。一旦執行緒獲得了遞迴鎖,同乙個執行緒再次獲取它將不阻塞;執行緒必須在每次獲取它時釋放一次。

雖然鎖可以防止程式出問題,但是使用鎖不得當是很容易出現死鎖。

死鎖 : 當執行緒a持有獨佔鎖a,並嘗試去獲取獨佔鎖b的同時,執行緒b持有獨佔鎖b,並嘗試獲取獨佔鎖a的情況下,就會發生ab兩個執行緒由於互相持有對方需要的鎖,而發生的阻塞現象,我們稱為死鎖。通俗的將就是一種相互等待無法結束的現象。

下面就演示一下在 python 中可能出現的死鎖

1、互斥鎖使用過程中在子函式內再次加鎖,導致死鎖。

import threading

import time

num =

0# 注意:在普通的互斥鎖中,在同乙個執行緒內如果存在乙個函式多次獲得鎖,就會出現死鎖。注意:遞迴鎖就不會。

llock = threading.lock(

)# 建立乙個互斥鎖

defadd_num

(lock)

:global num

lock.acquire(

) num +=

1 lock.release(

)def

run1

(n, lock)

:global num

print

('task '

,n) time.sleep(1)

lock.acquire(

)for i in

range

(1000000):

# lock.acquire()

add_num(lock)

# lock.release()

lock.release(

)print

(num)

defrun2

(n, lock)

:global num

print

('task '

,n) time.sleep(1)

lock.acquire(

)for i in

range

(1000000):

# lock.acquire()

add_num(lock)

# lock.release()

lock.release(

)print

(num)

if __name__ ==

'__main__'

: start_time = time.time(

)# 定義多執行緒 如果我們傳入的是互斥鎖,那麼就會出現死鎖,

t1 = threading.thread(target=run1, args=

('執行緒a'

, llock)

) t2 = threading.thread(target=run2, args=

('執行緒b'

, llock)

)# 啟動多執行緒

t1.start(

) t2.start(

)# 設定主線程等待子執行緒完成後退出,設定完後主執行緒會阻塞在這裡

t1.join(

) t2.join(

)print

(, time.time(

)- start_time)

2、無論使用遞迴鎖還是互斥鎖,當出現互相等待時,導致死鎖。
import threading

import time

'''互相等待的死鎖:

當鎖出現互相等待的時候就會出現死鎖。例如方法1 先將a加鎖,並且想獲取b的鎖,然而此時方法2先將b加鎖,再將b加鎖。由於方法1沒有得到b的鎖因此不會釋放。導致方法2無法獲取b的鎖。出現死鎖。

run1(a, b)

acquire(a) 將a加鎖

acquire(b) 將b加鎖

run2(, b)

acquire(b) 將b加鎖,前提是其他方法先釋放b的鎖

acquire(a)

'''a =

0b =

0# 建立乙個互斥鎖,就算使用遞迴鎖,這種相互等待的也會出現死鎖

locka = threading.lock(

)lockb = threading.lock(

)def

run1

(n):

global a

global b

print

('task '

,n) locka.acquire(

) a +=

1 time.sleep(1)

lockb.acquire(

) b +=

1 lockb.release(

) locka.release(

)print

(a)def

run2

(n):

global a

global b

print

('task '

,n) lockb.acquire(

) b +=

1 locka.acquire(

) a +=

1 locka.release(

) lockb.release(

)print

(a)if __name__ ==

'__main__'

: start_time = time.time(

)# 定義多執行緒

t1 = threading.thread(target=run1, args=

('執行緒a',)

) t2 = threading.thread(target=run2, args=

('執行緒b',)

)# 啟動多執行緒

t1.start(

) t2.start(

)# 設定主線程等待子執行緒完成後退出,設定完後主執行緒會阻塞在這裡

t1.join(

) t2.join(

)print

(, time.time(

)- start_time)

3、通過**來看互斥鎖和遞迴鎖的區別
import threading

import time

num =

0# 建立乙個遞迴鎖 在同乙個執行緒裡面可以連續呼叫多次acquire()獲得鎖,但是要保證呼叫acquire的次數和release的次數保持一致。

# 注意:在普通的互斥鎖中,在同乙個執行緒內如果存在乙個函式多次獲得鎖,就會出現死鎖。遞迴鎖就不會。下面具體例子說明

rlock = threading.rlock(

)# 建立乙個遞迴鎖

llock = threading.lock(

)# 建立乙個互斥鎖

defadd_num

(lock)

:global num

lock.acquire(

) num +=

1 lock.release(

)def

run1

(n, lock)

:global num

print

('task '

,n) time.sleep(1)

lock.acquire(

)for i in

range

(1000000):

# lock.acquire()

add_num(lock)

# lock.release()

lock.release(

)print

(num)

defrun2

(n, lock)

:global num

print

('task '

,n) time.sleep(1)

lock.acquire(

)for i in

range

(1000000):

# lock.acquire()

add_num(lock)

# lock.release()

lock.release(

)print

(num)

if __name__ ==

'__main__'

: start_time = time.time(

)# 定義多執行緒 如果我們傳入的是互斥鎖,那麼就會出現死鎖,

# t1 = threading.thread(target=run1, args=('執行緒a', llock))

# t2 = threading.thread(target=run2, args=('執行緒b', llock))

# 傳入遞迴鎖

t1 = threading.thread(target=run1, args=

('執行緒a'

, rlock)

) t2 = threading.thread(target=run2, args=

('執行緒b'

, rlock)

)# 啟動多執行緒

t1.start(

) t2.start(

)# 設定主線程等待子執行緒完成後退出,設定完後主執行緒會阻塞在這裡

t1.join(

) t2.join(

)print

(, time.time(

)- start_time)

python 執行緒死鎖示例

銀行轉賬 兩個賬戶同時給對方轉賬,模擬線程死鎖 from threading import thread,lock from time import sleep 賬戶類 class account def init self,id,balance,lock 每個賬戶自帶乙個鎖,只要數字balance...

Python多執行緒示例

直接使用threading.thread進行多執行緒實現,其中target為要執行的方法或函式,args為引數列表 方法或函式需要的值 結尾加 因為是元組。def pa n for i in range 10 time.sleep 2 print 這是執行緒 str n defpa2 n for i...

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 pri...