互斥鎖、死結和遞迴鎖,互斥鎖遞迴

來源:互聯網
上載者:User

互斥鎖、死結和遞迴鎖,互斥鎖遞迴
一、互斥鎖(Mutex)

   在上節最後我們講到了安全執行緒,線程同步能夠保證多個安全執行緒訪問競爭資源,最簡單的同步機制是引入互斥鎖。互斥鎖為資源引入一個狀態:鎖定/非鎖定。某個線程要更改共用資料時,先將其鎖定,此時資源的狀態為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態變成“非鎖定”,其他的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下資料的正確性。

  threading模組中定義了Lock類,可以方便的處理鎖定: 

#建立鎖lock = threading.Lock()#鎖定lock.acquire(blocking=True, timeout=-1) #釋放 lock.release() 

  還是以上節執行個體為例:

# -*- coding: UTF-8 -*-import threadingclass MyThread(threading.Thread):    def run(self):        global n        lock.acquire()        n += 1        lock.release()        print(self.name + ' set n to ' + str(n))n = 0lock = threading.Lock()if __name__ == '__main__':    for i in range(5):        t = MyThread()        t.start()    print('final num: %d' % n)

  輸出:

Thread-1 set n to 1Thread-2 set n to 2Thread-3 set n to 3Thread-4 set n to 4Thread-5 set n to 5final num: 5

  加鎖之後,我們可以確保資料的正確性

二、死結

  死結是指一個資源被多次調用,而多次調用方都未能釋放該資源就會造成一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死結狀態或系統產生了死結。

  2.1 一個線程內部多次加鎖卻沒有釋放  
import threadingclass MyThread(threading.Thread):    def run(self):        global n1, n2        lock.acquire()   # 加鎖        n1 += 1        print(self.name + ' set n1 to ' + str(n1))        lock.acquire()   # 再次加鎖        n2 += n1        print(self.name + ' set n2 to ' + str(n2))        lock.release()        lock.release()n1, n2 = 0, 0lock = threading.Lock()if __name__ == '__main__':    thread_list = []    for i in range(5):        t = MyThread()        t.start()        thread_list.append(t)    for t in thread_list:        t.join()    print('final num:%d ,%d' % (n1, n2))

  結果:

Thread-1 set n1 to 1# 會一直等待
  2.2 多個程式間相互調用引起死結
import threading,time def run1():    print("grab the first part data")    lock.acquire()    global num    num +=1    lock.release()    return numdef run2():    print("grab the second part data")    lock.acquire()    global  num2    num2+=1    lock.release()    return num2def 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.Lock()    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) 
 三、遞迴鎖

  上述兩個問題都可以使用python的遞迴鎖解決 

# 遞迴鎖rlock = threading.RLOCK()

  RLock內部維護著一個Lock和一個counter變數,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。這裡以例1為例,如果使用RLock代替Lock,則不會發生死結:

  

# -*- coding: UTF-8 -*-import threadingclass MyThread(threading.Thread):    def run(self):        global n1, n2        lock.acquire()   # 加鎖        n1 += 1        print(self.name + ' set n1 to ' + str(n1))        lock.acquire()   # 再次加鎖        n2 += n1        print(self.name + ' set n2 to ' + str(n2))        lock.release()        lock.release()n1, n2 = 0, 0lock = threading.RLock()if __name__ == '__main__':    thread_list = []    for i in range(5):        t = MyThread()        t.start()        thread_list.append(t)    for t in thread_list:        t.join()    print('final num:%d ,%d' % (n1, n2))

  輸出:

Thread-1 set n1 to 1Thread-1 set n2 to 1Thread-2 set n1 to 2Thread-2 set n2 to 3Thread-3 set n1 to 3Thread-3 set n2 to 6Thread-4 set n1 to 4Thread-4 set n2 to 10Thread-5 set n1 to 5Thread-5 set n2 to 15final num:5 ,15

  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.