資安

線程鎖的使用

本文來自於千鋒教育在阿里雲開發者社區學習中心上線課程《Python入門2020最新大課》,主講人姜偉。

線程鎖的使用

同步

當多個線程幾乎同時修改某一個共享數據的時候,需要進行同步控制。同步就是協同步調,按預定的先後次序進行運行。線程同步能夠保證多個線程安全訪問競爭資源,最簡單的同步機制是引入互斥鎖。

互斥鎖

互斥鎖為資源引入一個狀態:鎖定/非鎖定

某個線程要更改共享數據時,先將其鎖定,此時資源的狀態為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態變成“非鎖定”,其他的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數據的正確性。

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

# 創建鎖
mutex = threading.Lock()
# 鎖定
mutex.acquire()
# 釋放
mutex.release()

注意:

  • 如果這個鎖之前是沒有上鎖的,那麼acquire不會堵塞
  • 如果在調用acquire對這個鎖上鎖之前 它已經被 其他線程上了鎖,那麼此時acquire會堵塞,直到這個鎖被解鎖為止。
  • 和文件操作一樣,Lock也可以使用with語句快速的實現打開和關閉操作。

使用互斥鎖解決賣票問題

import threading
import time

ticket = 20

# 創建一把鎖
lock = threading.Lock()


def sell_ticket():
    global ticket
    while True:
        print('呵呵呵')
        print('哈哈哈')
        print('ddd')
        print('ppp')
        print('sss')
        print('ttt')
        print('xxx')
        lock.acquire()  # 加同步鎖
        if ticket > 0:
            time.sleep(1)
            ticket -= 1
            lock.release()
            print('{}賣出一張票,還剩{}張'.format(threading.current_thread().name, ticket))
        else:
            lock.release()
            print('票賣完了')
            break


t1 = threading.Thread(target=sell_ticket, name='線程1')
t2 = threading.Thread(target=sell_ticket, name='線程2')

t1.start()
t2.start()

上鎖過程:

當一個線程調用鎖的acquire()方法獲得鎖時,鎖就進入“locked”狀態。

每次只有一個線程可以獲得鎖。如果此時另一個線程試圖獲得這個鎖,該線程就會變為“blocked”狀態,稱為“阻塞”,直到擁有鎖的線程調用鎖的release()方法釋放鎖之後,鎖進入“unlocked”狀態。

線程調度程序從處於同步阻塞狀態的線程中選擇一個來獲得鎖,並使得該線程進入運行(running)狀態。

總結

鎖的好處:
確保了某段關鍵代碼只能由一個線程從頭到尾完整地執行

鎖的壞處:

  • 阻止了多線程併發執行,包含鎖的某段代碼實際上只能以單線程模式執行,效率就大大地下降了。
  • 由於可以存在多個鎖,不同的線程持有不同的鎖,並試圖獲取對方持有的鎖時,可能會造成死鎖。

配套視頻

Leave a Reply

Your email address will not be published. Required fields are marked *