一、線程鎖(互斥鎖)
在一個程序內,主進程可以啟動很多個線程,這些線程都可以訪問主進程的內存空間,在Python中雖然有了GIL,同一時間只有一個線程在運行,可是這些線程的調度都歸系統,操作系統有自身的調度規則,所以就可能造成,
- 假設兩個線程都在訪問 global count= 0, 每個進程都會執行 count +=1 。(1)(2)(3)第一個線程申請GIL然后,讀取global count到及進程到 cpu ,(4)然后cpu執行到一半,(5)把這個線程停了,將上下文保存到自身寄存器中。注意這時候沒返回結果。這時候解釋器就會把GIL釋放,
- (6)(7)(8)第二個線程申請GIL執行如上步驟,讀取count= 0 ,cpu計算結束后將結果count=1 返回,(10)(11)解釋器拿到結果進行賦值,此時count=1,這個進程運行結束,(12)(13)然后cpu從寄存器中第一個線程的執行狀態,繼續執行,注意這個讀取的是寄存器中的上下文,就是第一次執行時 count= 0,及第一個線程的上下文。計算結果返回count =1 返回。就造成了結果的錯誤。

1.1 python中的線程鎖(互斥鎖mutex)
使用threading模塊中的Lock類,得到一個全局鎖實例。然后 Lock()實例下 有一個 acquire 方法為加鎖, release 方法釋放鎖
import threading
count = 0
lock = threading.Lock() #申請一個鎖
def count_():
global count #聲明為全局變量
lock.acquire() #加鎖,鎖釋放前不予許其他程序執行
count += 1
lock.release() #執行完 ,釋放鎖
thread_list = []
for i in range(10):
t = threading.Thread(target= count_)
t.start()
thread_list.append(t)
for t in thread_list:
t.join() #主程序等待所有程序執行完畢
print('Count:{: ^4}'.format(count))
1.2 遞歸鎖
基本用不上,主要目的就是防止鎖里面加鎖,然后程序無法解鎖退出。
import threading,time
def run1():
print("grab the first part data")
lock.acquire()
global num
num +=1
lock.release()
return num
def run2():
print("grab the second part data")
lock.acquire()
global num2
num2+=1
lock.release()
return num2
def run3():
lock.acquire()
res = run1()
print('--------between run1 and run2-----')
res2 = run2()
lock.release()
print(res,res2)
if __name__ == '__main__':
num,num2 = 0,0
lock = threading.RLock()
for i in range(10):
t = threading.Thread(target=run3)
t.start()
while threading.active_count() != 1:
print(threading.active_count())
else:
print('----all threads done---')
print(num,num2)
