死鎖當多個執行緒幾乎同時修改某乙個共享資料的時候,需要進行同步控制。執行緒同步能夠保證多個執行緒安全訪問競爭資源,最簡單的同步機制是引入互斥鎖。
互斥鎖為資源引入乙個狀態:鎖定/非鎖定
某個執行緒要更改共享資料時,先將其鎖定,此時資源的狀態為「鎖定」,其他執行緒不能更改;直到該執行緒釋放資源,將資源的狀態變成「非鎖定」,其他的執行緒才能再次鎖定該資源。互斥鎖保證了每次只有乙個執行緒進行寫入操作,從而保證了多執行緒情況下資料的正確性。
threading模組中定義了lock類,可以方便的處理鎖定:
# 建立鎖
q = threading.lock(
)# 鎖定
q.acquire(
)# 釋放
q.release(
)
注意:
如果這個鎖之前是沒有上鎖的,那麼acquire不會堵塞
如果在呼叫acquire對這個鎖上鎖之前 它已經被 其他執行緒上了鎖,那麼此時acquire會堵塞,直到這個鎖被解鎖為止
使用互斥鎖完成2個執行緒對同乙個全域性變數各加1000000次的操作
"""
@time :2020/2/12 15:50
@coding :utf-8
@auth :bing.
@ide :pycharm
@file :12.互斥鎖.py
@motto:move on
"""from threading import thread
from threading import lock
g_num=
0# 建立乙個全域性鎖物件
lock = lock(
)def
work1
(num)
:global g_num
lock.acquire(
)# 加鎖
for i in
range
(num)
: g_num+=
1 lock.release(
)# 解鎖
print
("in work1--->"
,g_num)
defwork2
(num)
:global g_num
lock.acquire(
)# 加鎖
for i in
range
(num)
: g_num+=
1 lock.release(
)# 解鎖
print
("in work2--->"
,g_num)
defmain()
: t1 = thread(target=work1,args=
(1000000,)
) t2 = thread(target=work2,args=
(1000000,)
) t1.start(
) t2.start(
) t2.join(
)if __name__ ==
'__main__'
: main(
)print
("main--->"
,g_num)
執行結果:
in work1---
>
1000000
in work2---
>
2000000
main---
>
2000000
當乙個執行緒呼叫鎖的acquire()方法獲得鎖時,鎖就進入「locked」狀態。
每次只有乙個執行緒可以獲得鎖。如果此時另乙個執行緒試圖獲得這個鎖,該執行緒就會變為「blocked」狀態,稱為「阻塞」,直到擁有鎖的執行緒呼叫鎖的release()方法釋放鎖之後,鎖進入「unlocked」狀態。
執行緒排程程式從處於同步阻塞狀態的執行緒中選擇乙個來獲得鎖,並使得該執行緒進入執行(running)狀態。
鎖的好處:
確保了某段關鍵**只能由乙個執行緒從頭到尾完整地執行
鎖的壞處:
阻止了多執行緒併發執行,包含鎖的某段**實際上只能以單執行緒模式執行,效率就大大地下降了
由於可以存在多個鎖,不同的執行緒持有不同的鎖,並試圖獲取對方持有的鎖時,可能會造成死鎖
在多個執行緒共享資源的時候,如果兩個執行緒分別占有一部分資源,並且同時等待對方的資 源,就會造成死鎖現象。
如果鎖之間相互巢狀,就有可能出現死鎖。因此盡量不要出現鎖之間的巢狀。
儘管死鎖很少發生,但一旦發生就會造成應用的停止響應。下面看乙個死鎖的例子:
"""
@time :2020/2/12 16:09
@coding :utf-8
@auth :bing.
@ide :pycharm
@file :13.死鎖.py
@motto:move on
"""import time
from threading import lock
from threading import thread
lock1 = lock(
)lock2 = lock(
)def
work1
(num)
: lock1.acquire(
)# lock1上鎖
time.sleep(1)
print
("in work1"
) lock2.acquire(
)# lock2上鎖
print
("work1------"
) lock2.release(
)# lock2解鎖
lock1.release(
)# lock1解鎖
defwork2
(num)
: lock2.acquire(
)# lock2加鎖
print
("in work2"
) lock1.acquire(
)# lock1加鎖
print
("work2------"
) lock1.release(
)# lock1解鎖
lock2.release(
)# lock2解鎖
if __name__ ==
'__main__'
: t1=thread(target=work1,args=
(1000000,)
) t2 = thread(target=work2, args=
(1000000,)
) t1.start(
) t2.start(
)
執行結果:
避免死鎖
-程式設計時要盡量避免(銀行家演算法)
-新增超時時間等
附錄-銀行家演算法
背景簡介:
在銀行中,客戶申請貸款的數量是有限的,每個客戶在第一次申請貸款時要宣告完成該專案所需的最大資金量,在滿足所有貸款要求時,客戶應及時歸還。銀行家在客戶申請的貸款數量不超過自己擁有的最大值時,都應盡量滿足客戶的需要。在這樣的描述中,銀行家就好比作業系統,資金就是資源,客戶就相當於要申請資源的程序。
銀行家演算法是一種最有代表性的避免死鎖的演算法。在避免死鎖方法中允許程序動態地申請資源,但系統在進行資源分配之前,應先計算此次分配資源的安全性,若分配不會導致系統進入不安全狀態,則分配,否則等待。為實現銀行家演算法,系統必須設定若干資料結構。
安全序列是指乙個程序序列是安全的,即對於每乙個程序pi(1≤i≤n),它以後尚需要的資源量不超過系統當前剩餘資源量與所有程序pj (j < i )當前占有資源量之和。(即在分配過程中,不會出現某一程序後續需要的資源量比其他所有程序及當前剩餘資源量總和還大的情況)
注:存在安全序列則系統是安全的,如果不存在則系統不安全,但不安全狀態不一定引起死鎖。
原理過程:
系統給當前程序分配資源時,先檢查是否安全:
在滿足當前的程序x資源申請後,是否還能有足夠的資源去滿足下乙個距最大資源需求最近的程序(如某程序最大需要5個單位資源,已擁有1個,還尚需4個),若可以滿足,則繼續檢查下乙個距最大資源需求最近的程序,若均能滿足所有程序,則表示為安全,可以允許給當前程序x分配其所需的資源申請,否則讓該程序x進入等待。
(注:檢查過程中,每擬滿足乙個程序,則進行下個檢查時,當前可用資源為**上乙個程序資源的總值,每滿足乙個程序表示此程序已結束,資源可**。)
python 互斥鎖,死鎖
同步與非同步之間的區別 1.同步 可以理解為執行緒a和b一塊配合工作,a執行到一定程度時要依靠b的某個結 果,於是停下來示意b執行,b執行完將結果給a,然後a繼續執行。2.非同步 非同步是指程序不需要一直等待下去,而是繼續執行下面的操作,不管其他程序的狀態,當有資訊返回的時候會通知程序進行處理,這樣...
python 互斥鎖 死鎖
在多執行緒下,全域性變數是共享的,但是在兩個執行緒同時使用乙個全域性變數時,會出現這麼乙個情況,當a讀取了全域性變數a,b也讀取全域性變數a,a對a進行了 1操作,但是b是讀取a沒有進行一次 1操作之前的資料,然後b也進行 1操作,這就導致這錯誤的出現。為了防止這個錯誤的出現,所以引進互斥鎖。使用鎖...
python 互斥鎖與死鎖
一.概念原理 當多個執行緒幾乎同時修改某乙個共享資料的時候,需要進行同步控制 執行緒同步能夠保證多個執行緒安全訪問競爭資源,最簡單的同步機制是引入互斥鎖。互斥鎖為資源引入乙個狀態 鎖定 非鎖定。某個執行緒要更改共享資料時,先將其鎖定,此時資源的狀態為 鎖定 其他執行緒不能更改 直到該執行緒釋放資源,...