赞
赏
Python 的 threading 模块提供了 Lock 和 RLock 两个类,即互斥锁和递归锁。
在 Python 中,互斥锁如果嵌套了多个锁之后,会将自己锁死永远都出不来了。 这个时候可以使用递归锁,它相当于一个 字典,记录了锁的门与锁的对应值,当开门的时候会根据对应来开锁。
Python 的递归锁,即 threading.RLock。RLock 内部维护着一个 Lock 和一个 counter 变量,counter 记录了 acquire 的次数,从而使得资源可以被多次 acquire。直到一个线程所有的 acquire 都被 release,其他的线程才能获得资源。
from threading import Thread
# 创建递归锁
lock = threading.RLock()
# 对需要访问的资源加锁
lock.acquire()
lock.acquire()
# 资源访问结束解锁
lock.release()
lock.release()
递归锁的使用,需要使用 threading.RLock() 创建一个递归锁对象,接着对需要加锁访问的资源使用 lock.acquire()
进行加锁即可,最后,资源访问结束,使用 lock.release()
进行解锁即可。
递归锁与互斥锁的不同之处在于,我们可以同时调用多次 lock.acquire() 对互斥资源进行加锁,而互斥锁却不可以,如果互斥锁多次进行加锁,则会导致死锁。
使用 RLock 递归锁操作临界资源
import threading
num = 0
# 创建互斥锁
lock = threading.Lock()
def handler_incry():
global num
lock.acquire()
for i in range(100000):
num += 1
print("handler_incry done, num =", num)
lock.release()
def handler_decry():
global num
lock.acquire()
for i in range(100000):
num -= 1
print("handler_decry done, num =", num)
lock.release()
if __name__ == '__main__':
print("嗨客网(www.haicoder.net)")
# 创建线程
t1 = threading.Thread(target=handler_incry)
t2 = threading.Thread(target=handler_decry)
# 启动线程
t1.start()
t2.start()
t1.join()
t2.join()
程序运行后,控制台输出如下:
首先,我们定义了一个 int 类型的全局变量 num
,同时,我们使用 threading.Lock() 创建了一个互斥锁对象 lock。
接着,我们创建了一个 handler_incry
函数 和一个 handler_decry
函数,handler_incry
函数使用 for 循环 将全局变量 num
的值加 100000 次,执行完毕后,打印当前的 num 的值。
handler_decry
函数将全局变量 num
的减 100000 次,执行完毕后,打印当前的 num 的值,同时,我们创建了两个线程 t1 和 t2,他们的线程处理函数是我们上面定义的 handler_decry
和 handler_incry
。
最后,在 main 函数,我们开启了两个线程,并且使用 join 等待线程的结束。理所当然,我们在多线程操作全局变量的时候,需要使用 lock.acquire() 对临界资源进行加锁,同时,临界资源访问结束后,需要使用 lock.release() 对临界资源进行解锁。现在,我们修改程序为如下:
import threading
num = 0
# 创建互斥锁
lock = threading.Lock()
def handler_incry():
global num
lock.acquire()
lock.acquire()
for i in range(100000):
num += 1
print("handler_incry done, num =", num)
lock.release()
lock.release()
def handler_decry():
global num
lock.acquire()
lock.acquire()
for i in range(100000):
num -= 1
print("handler_decry done, num =", num)
lock.release()
lock.release()
if __name__ == '__main__':
print("嗨客网(www.haicoder.net)")
# 创建线程
t1 = threading.Thread(target=handler_incry)
t2 = threading.Thread(target=handler_decry)
# 启动线程
t1.start()
t2.start()
t1.join()
t2.join()
程序运行,如下:
我们在对临界资源进行修改与访问时,同时调用了两次互斥锁进行加锁与解锁操作,此时程序没有任何输出,因为,此时的程序就死锁了,因此,我们可以看出,互斥锁不可以使用同一把锁对临界资源进行多次加锁,现在我们将程序修改如下:
import threading
num = 0
# 创建递归锁
lock = threading.RLock()
def handler_incry():
global num
lock.acquire()
lock.acquire()
for i in range(100000):
num += 1
print("handler_incry done, num =", num)
lock.release()
lock.release()
def handler_decry():
global num
lock.acquire()
lock.acquire()
for i in range(100000):
num -= 1
print("handler_decry done, num =", num)
lock.release()
lock.release()
if __name__ == '__main__':
print("嗨客网(www.haicoder.net)")
# 创建线程
t1 = threading.Thread(target=handler_incry)
t2 = threading.Thread(target=handler_decry)
# 启动线程
t1.start()
t2.start()
t1.join()
t2.join()
程序运行,如下:
这次,我们只是将互斥锁换成了递归锁,我们看到,这次程序运行正常,即,递归锁是可以使用同一把锁对临界资源进行多次加锁操作的。
在 Python 中,互斥锁如果嵌套了多个锁之后,会将自己锁死永远都出不来了。 这个时候可以使用递归锁,它相当于一个字典,记录了锁的门与锁的对应值,当开门的时候会根据对应来开锁。python 互斥锁语法:
from threading import Thread
# 创建递归锁
lock = threading.RLock()
# 对需要访问的资源加锁
lock.acquire()
lock.acquire()
# 资源访问结束解锁
lock.release()
lock.release()