48_並發編程-線程-資源共享/鎖
阿新 • • 發佈:2018-10-26
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_並發編程-線程-資源共享/鎖