如果您嘗試運行下面提供的代碼,鎖對象將在第一次調用acquire()
方法時獲得鎖,但第二次不會。
為什么會這樣?因為正常的鎖對象一旦被獲取就不能被重新獲取,即使相同的線程試圖這樣做。
但是為什么會有人嘗試兩次調用acquire()
方法呢?讓我們舉一個簡單的例子來演示這個簡單的鎖定問題:
lock = threading.Lock()
def get_first_line():
lock.acquire()
try:
# read some file and get the first line
finally:
lock.release()
return data
def get_second_line():
lock.acquire()
try:
# read the same file and get the second line
finally:
lock.release()
return data
在上面的代碼中,我們有兩個不同的函數從共享資源中讀取不同部分的數據。我們使用了鎖定機制來防止任何其他線程在我們的線程讀取文件時修改文件的數據。
現在考慮您想要逐個調用這兩個函數,您將這樣做:
first = get_first_line()
second = get_second_line()
return first, second
但是這個調用仍然不是線程安全的,因為當您從共享資源中讀取數據時,在兩個函數調用之間可以有任何其他線程可以修改共享資源的內容。
為了避免這種情況,我們可以獲取一個鎖,然后調用這兩個函數:
lock.acquire()
try:
first = get_first_line()
second = get_second_line()
finally:
lock.release()
return first, second
但是,這段代碼不會起作用,因為我們將在同一線程內的鎖對象上調用acquire()
,試圖在調用函數之前已經獲取的函數內再次獲取鎖。
因此,在這種情況下,不能使用基本的鎖對象。對于這樣的情況我們有RLock
類。
對象:Python 多線程
RLock 代表可重入鎖。同一個線程可以多次獲取可重入鎖。
RLock 對象也有兩個可以調用的方法,它們是:
acquire()
方法release()
方法
這里有一個簡單的例子來演示RLock
對象的工作:
如果我們使用RLock
對象,那么簡單的鎖定問題示例中的代碼也將毫無問題地工作:
lock = threading.RLock()
lock.acquire()
try:
first = get_first_line()
second = get_second_line()
finally:
lock.release()
return first, second
上面的代碼可以正常工作。