1. 程式人生 > >48_並發編程-線程-資源共享/鎖

48_並發編程-線程-資源共享/鎖

from com 就是 互斥 獲得 爭奪 例子 counter 執行過程

一、數據共享   多個線程內部有自己的數據棧,數據不共享;全局變量在多個線程之間是共享的。 技術分享圖片
 1 # 線程數據共享不安全加鎖
 2 
 3 import time
 4 from threading import Thread, Lock
 5 
 6 
 7 num = 100
 8 
 9 def func(t_lock):
10     global num
11     t_lock.acquire()
12     mid = num
13     mid -= 1
14     time.sleep(0.01) # 設置一個時間,模擬數據修改時,先從內存中拿出作修改,在把結果放回去的時間差
15 num = mid 16 t_lock.release() 17 18 if __name__ == __main__: 19 20 t_lock = Lock() 21 22 t_lst = [] 23 for i in range(10): 24 t_thread = Thread(target=func, args=(t_lock,)) 25 t_lst.append(t_thread) 26 t_thread.start() 27 [t_obj.join() for t_obj in
t_lst] #必須加join,因為主線程和子線程不一定誰快,一般都是主線程快一些,所有我們要等子線程執行完畢才能看出效果 28 29 print(主線程結束!, num) # 結果為90
數據共享實例 二、同步鎖(互斥鎖) - 產生死鎖   進程也有死鎖與遞歸鎖,在進程那裏忘記說了,放到這裏一切說了額,進程的死鎖和線程的是一樣的,而且一般情況下進程之間是數據不共享的,不需要加鎖,由於線程是對全局的數據共享的,所以對於全局的數據進行操作的時候,要加鎖。   死鎖: 是指兩個或兩個以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程,如下就是死鎖
技術分享圖片
 1 from threading import Thread,Lock
 2 import time
 3 
 4 class MyThread(Thread):
 5     def run(self):
 6         self.func1()
 7         self.func2()
 8     def func1(self):
 9         mutexA.acquire()
10         print(\033[41m%s 拿到A鎖>>>\033[0m %self.name)
11         mutexB.acquire()
12         print(\033[42m%s 拿到B鎖>>>\033[0m %self.name)
13         mutexB.release()
14         mutexA.release()
15 
16     def func2(self):
17         mutexB.acquire()  
18         print(\033[43m%s 拿到B鎖???\033[0m %self.name)
19         time.sleep(2)
20 #分析:當線程1執行完func1,然後執行到這裏的時候,拿到了B鎖,線程2執行func1的時候拿到了A鎖,那麽線程2還要繼續執行func1裏面的代碼,再去拿B鎖的時候,發現B鎖被人拿了,那麽就一直等著別人把B鎖釋放,那麽就一直等著,等到線程1的sleep時間用完之後,線程1繼續執行func2,需要拿A鎖了,但是A鎖被線程2拿著呢,還沒有釋放,因為他在等著B鎖被釋放,那麽這倆人就尷尬了,你拿著我的老A,我拿著你的B,這就尷尬了,倆人就停在了原地
21         
22         mutexA.acquire()
23         print(\033[44m%s 拿到A鎖???\033[0m %self.name)
24         mutexA.release()
25         mutexB.release()
26 
27 if __name__ == __main__:
28 
29     mutexA=Lock()    # 同步鎖必須這樣創建
30     mutexB=Lock()
31     for i in range(10):
32         t=MyThread()
33         t.start()
34 
35 ‘‘‘
36 Thread-1 拿到A鎖>>>
37 Thread-1 拿到B鎖>>>
38 Thread-1 拿到B鎖???
39 Thread-2 拿到A鎖>>>
40 然後就卡住,死鎖了
41 ‘‘‘
死鎖現象

技術分享圖片

三、解決死鎖方案 - 遞歸鎖   解決方法,遞歸鎖,在Python中為了支持在同一線程中多次請求同一資源,python提供了可重入鎖RLock。   這個RLock內部維護著一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。上面的例子如果使用RLock代替Lock,則不會發生死鎖: 技術分享圖片
 1 import time
 2 from threading import Thread,RLock
 3 
 4 
 5 class MyThread(Thread):
 6 
 7     def __init__(self, lockA, lockB):
 8         super().__init__()
 9         self.lockA = lockA
10         self.lockB = lockB
11     def run(self):
12         self.func1()
13         self.func2()
14 
15     def func1(self):
16         self.lockA.acquire()
17         print(我是func1)
18         self.lockB.acquire()
19         print(func1中有其他事)
20         self.lockB.release()
21         self.lockA.release()
22 
23     def func2(self):
24         self.lockB.acquire()
25         print(我是func2)
26         time.sleep(0.5)
27         self.lockA.acquire()
28         print(func2中有什麽事)
29         self.lockA.release()
30         self.lockB.release()
31 
32 if __name__ == __main__:
33 
34     lockA = lockB = RLock()
35 
36     t1 = MyThread(lockA, lockB)
37     t1.start()
38     t2 = MyThread(lockA, lockB)
39     t2.start()
40     print(嗯嗯,兩人不錯)
遞歸鎖

技術分享圖片

48_並發編程-線程-資源共享/鎖