互斥鎖
一.概念原理
當多個線程幾乎同時修改某一個共享數據的時候,需要進行同步控制
線程同步能夠保證多個線程安全訪問競爭資源,最簡單的同步機制是引入互斥鎖。
互斥鎖爲資源引入一個狀態:鎖定/非鎖定。
某個線程要更改共享數據時,先將其鎖定,此時資源的狀態爲“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態變成“非鎖定”,其他的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數據的正確性。
二.示例
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)
def work2(num):
global g_num
lock.acquire()#加鎖
for i in range (num):
g_num+=1
lock.release()#解鎖
print("work2-->",g_num)
def main():
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
work2--> 2000000
main--> 2000000
其中,
鎖定方法acquire可以有一個參數。
如果參數設定爲True,則當前線程會堵塞,直到獲取到這個鎖爲止(如果沒有指定,那麼默認爲True)
如果設定參數爲False,則當前線程不會堵塞
鎖的好處:
確保了某段關鍵代碼只能由一個線程從頭到尾完整地執行
鎖的壞處:
阻止了多線程併發執行,包含鎖的某段代碼實際上只能以單線程模式執行,效率就大大地下降了
由於可以存在多個鎖,不同的線程持有不同的鎖,並試圖獲取對方持有的鎖時,可能會造成死鎖
死鎖
一.概念
在多道程序系統中,由於多個進程的併發執行,改善了系統資源的利用率並提高了系統的處理能力。
然而,多個進程的併發執行也帶來了新的問題——死鎖。所謂死鎖是指多個進程因競爭資源而造成的一種僵局,若無外力作用,這些進程都將無法向前推進。
二.示例
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解鎖
def work2(num):
lock2.acquire()#lock2加鎖
print("in work2")
lock1.acquire()#lock1加鎖
print("work1-----")
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()
結果:
in work2
in work1
看了上面的例子我們來說說防止死鎖的加鎖機制
問題:
你正在寫一個多線程程序,其中線程需要一次獲取多個鎖,此時如何避免死鎖問題。
解決方案:
在多線程程序中,死鎖問題很大一部分是由於線程同時獲取多個鎖造成的。舉個例子:一個線程獲取了第一個鎖,然後在獲取第二個鎖的 時候發生阻塞,那麼這個線程就可能阻塞其他線程的執行,從而導致整個程序假死。 解決死鎖問題的一種方案是爲程序中的每一個鎖分配一個唯一的id,然後只允許按照升序規則來使用多個鎖。