線程同步中的一些鎖、條件、信號量的解析

python threading 中的 Lock, RLock, Condition, Semaphore, Event

這些內容主要是用來控制在併發過程中,線程的同步行爲的。

Lock

lock 是在控制同步中 常見且基礎的對象。通過這個對象可以控制共享資源的串行訪問。

需要注意: 鎖的獲取、釋放, 防止死鎖!

from threading import Lock

lock = Lock()

with lock:
    pass

當然可以添加兩個參數, blocking, timeout 用來控制怎麼獲取鎖。
可以阻塞, 可以超時,默認是阻塞無超時,就是一直等待下去。

默認參數: timeout=-1, blocking=True

RLock

重入鎖。

爲什麼會出現:當時用普通的鎖的時候,如果已經獲取了鎖,再次獲取的時候,就會永久阻塞。也就是鎖不會被釋放
也不能再次被獲取。這就造成了死鎖。

解決方式:就是提供了一個類型的鎖,重入鎖, RLock

特點:就是已經獲取到鎖後當前線程可以再次獲取。

內部實現: 基本鎖是Lock, 內部是通過獲取當前鎖的持有人的ID, 每次獲取的時候進行判斷,是同一個就返回並給計數加1。
釋放則不會直接把鎖釋放掉,而是計數減一,直到計數爲0,才真正的釋放屌內部鎖

from threading import RLock

r_lock = RLock()

with r_lock:
    print(r_lock)
    with r_lock:
        print(r_lock)

輸出:

<locked _thread.RLock object owner=5832 count=1 at 0x0000000002158B40>
<locked _thread.RLock object owner=5832 count=2 at 0x0000000002158B40>

可看到 count 變爲了2, owner表示持有人爲5832

Condition

條件,條件變量, 狀態

爲什麼會出現: 假如有一個需求 是在某些順序代碼中 要不止一次控制暫停等待或者喚醒
如果單單的只是用一把普通的鎖,多個任務(併發的同樣的任務或是同時執行的不同的任務)也就只能停止等待一次,獲取了鎖,執行完就釋放了。
那麼如果要多次等待幾次,那就同時多整幾把鎖,放到隊列裏面, 並且不同的併發的線程中的等待的鎖不能一樣。但是可以通過接口釋放這些鎖,達到喚醒目的。

同時,因爲處於併發環境下,協調這些鎖的時候爲了避免鎖隊列內容不同步,需要有一把串行鎖,保證協調的時候串行執行。同時也是防止等待超時之後直接順序執行代碼

怎麼實現呢:

材料: 同步鎖,鎖隊列

實現方式: 在需要等待的時候,先保證持有同步鎖,生成一把普通的鎖,加進鎖隊列,然後進行等待,同時釋放轉儲同步鎖,讓其他線程使用。
同時要注意鎖隊列的清除,把超時的鎖清除,和被喚醒的鎖清除。清除完畢之後要重新獲取同步鎖,防止因阻塞鎖超時釋放而自動執行代碼

通知接口: 通知接口會將所有的阻塞鎖進行釋放,讓等待這些鎖的斷點進行執行。

需要注意的是:
在使用waitnotify的時候要先獲取同步鎖。

不關鍵的關鍵內容: wait 裏面是怎麼通過一把鎖使得當前線程暫停的。

基本方式如下:

is_block = True
timeout = 3

from threading import Lock
lock_queue = []

simple_lock = Lock()
lock_queue.append(simple_lock)
simple_lock.acquire()
# 釋放同步鎖,讓其他線程使用

simple_lock.acquire(block=is_block, timeout=timeout)
# 這樣 這個順序代碼就被阻塞到這個地方了

其中這個simple_lock 就是用來阻斷代碼執行,只有等到 simple_lock 被其他線程釋放,或是超時才能繼續往下執行代碼。

另外,超時之後,還要爭用同步鎖。

samephore

信號量

相對於普通的鎖,增加了併發控制,可以認爲的控制同時執行的線程個數

內部實現基於condition

event

事件

裏面增加了標記,被稱爲事件信號,是condition的又一包裝。 當標記被設置之後,喚醒所有等待事件信號的線程。
操作相對condition更加簡單

內部實現:condition

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章