Lock与RLock的区别

往期推荐

Python多线程的使用
Python线程池的使用
Python多线程的安全问题

B站同名【有温度的算法】已经上线
想观看视频讲解的同学
点击此处直达B站

介绍

在上节中为大家说明了线程访问临界资源,必须互斥的进行,从而引出了锁。在Python的threading模块中,为我们提供了Lock方法与RLock方法,都具备锁的功能,本节就为大家介绍一下两者在应用时的不同。

区别一

Lock被称为原始锁,一个线程只能请求一次;RLock被称为重入锁,可以被一个线程请求多次,即锁中可以嵌套锁,所以在使用RLock时,acquire与release必须成对出现。


import threading

def main():
    lock.acquire()
    print('第一道锁')
    lock.acquire()
    print('第二道锁')
    lock.release()
    lock.release()

if __name__ == '__main__':
    lock = threading.Lock()
    main()

我们定义Lock锁,同时在main函数中定义2个锁,在进入第一个锁后打印“第一道锁”,在进入第二个锁后打印“第二道锁”,然后在主线程中运行(只有这一个线程)。

# 输出
第一道锁

我们会发现这时程序只会打印“第一道锁”,而且程序既没有终止,也没有继续运行。这是因为Lock锁在同一线程内第一次加锁之后还没有释放时,就进行了第二次acquire请求,导致无法执行release,所以锁永远无法释放,这就是死锁。

import threading

def main():
    lock.acquire()
    print('第一道锁')
    lock.acquire()
    print('第二道锁')
    lock.release()
    lock.release()
if __name__ == '__main__':
    lock = threading.RLock()
    main()

如果我们使用RLock,就不会发生死锁的状态。

# 输出
第一道锁
第二道锁

因为RLock可以被一个线程请求多次,即锁中可以嵌套锁。

区别二

当Lock处于锁定状态时,不属于特定线程,可在另一个线程中进行解锁释放;而RLock只有当前线程才能释放本线程上的锁,不可由其他线程进行释放,所以在使用RLock时,acquire与release必须成对出现,即解铃还须系铃人。

import threading

def main():
    lock.release()
    print("在子线程解锁后打印")
if __name__ == '__main__':
    lock = threading.Lock()
    lock.acquire()
    t = threading.Thread(target=main)
    t.start()

在主线程中定义Lock锁,然后上锁,再创建一个子线程t运行main函数释放锁,结果正常输出,说明主线程上的锁,可由子线程解锁。

# 输出
在子线程解锁后打印

如果把上面的锁改为RLock则报错。在实际中设计程序时,我们会将每个功能分别封装成一个函数,每个函数中都可能会有临界区域,所以就需要用到RLock。

import threading
import time

def fun_1():
    print('开始')
    time.sleep(1)
    lock.acquire()
    print("第一道锁")
    fun_2()
    lock.release()

def fun_2():
    lock.acquire()
    print("第二道锁")
    lock.release()

if __name__ == '__main__':
    lock = threading.RLock()
    t1 = threading.Thread(target=fun_1)
    t2 = threading.Thread(target=fun_1)
    t1.start()
    t2.start()

我们定义RLock锁,然后设置t1与t2两个线程,两个线程分别运行fun_1,都打印“开始”,然后进入到临界区域,fun_1先上锁后打印“第一道锁”,然后进入fun_2,上第二道锁后打印“第二道锁”,之后解除第二道锁再解除第一道锁后执行结束。t2在t1上锁后被堵塞,等t1完全解锁后t2才继续运行。


# 输出
开始
开始
第一道锁
第二道锁
第一道锁
第二道锁

如果此例用Lock锁的话,由于在同一线程中fun_1上了一把锁,在进入fun_2中会因为无法第二次上锁而导致本线程阻塞,程序阻塞之后又无法释放锁,就会导致程序死锁。在实际的复杂程序中,RLock使用的更多一些。

获取本章代码集合,可关注公众号【AI有温度】,在后台回复【多线程】即可获取。
在这里插入图片描述

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页
评论

打赏作者

有温度的算法

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值