Python递归锁

Python递归锁教程

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()

程序运行后,控制台输出如下:

11 python线程递归锁.png

首先,我们定义了一个 int 类型的全局变量 num ,同时,我们使用 threading.Lock() 创建了一个互斥锁对象 lock。

接着,我们创建了一个 handler_incry 函数 和一个 handler_decry 函数,handler_incry 函数使用 for 循环 将全局变量 num 的值加 100000 次,执行完毕后,打印当前的 num 的值。

handler_decry 函数将全局变量 num 的减 100000 次,执行完毕后,打印当前的 num 的值,同时,我们创建了两个线程 t1 和 t2,他们的线程处理函数是我们上面定义的 handler_decryhandler_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()

程序运行,如下:

12 python线程递归锁.png

我们在对临界资源进行修改与访问时,同时调用了两次互斥锁进行加锁与解锁操作,此时程序没有任何输出,因为,此时的程序就死锁了,因此,我们可以看出,互斥锁不可以使用同一把锁对临界资源进行多次加锁,现在我们将程序修改如下:

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()

程序运行,如下:

13 python线程递归锁.png

这次,我们只是将互斥锁换成了递归锁,我们看到,这次程序运行正常,即,递归锁是可以使用同一把锁对临界资源进行多次加锁操作的。

Python递归锁教程总结

在 Python 中,互斥锁如果嵌套了多个锁之后,会将自己锁死永远都出不来了。 这个时候可以使用递归锁,它相当于一个字典,记录了锁的门与锁的对应值,当开门的时候会根据对应来开锁。python 互斥锁语法:

from threading import Thread # 创建递归锁 lock = threading.RLock() # 对需要访问的资源加锁 lock.acquire() lock.acquire() # 资源访问结束解锁 lock.release() lock.release()