python多线程中的死锁和递归锁用法

冷炫風刃
发布: 2025-12-01 20:24:06
原创
207人浏览过
死锁是多线程竞争资源时因循环等待导致程序卡住的现象,如线程A持lock1等lock2、B持lock2等lock1;避免方法是统一加锁顺序并使用RLock支持同线程重复加锁,防止自我阻塞。

python多线程中的死锁和递归锁用法

在Python多线程编程中,死锁(Deadlock)是一个常见且棘手的问题。它通常发生在多个线程竞争多个锁资源时,彼此相互等待对方释放锁,导致所有线程都无法继续执行。

什么是死锁?

假设有两个线程 A 和 B,以及两把锁 lock1 和 lock2:

  • 线程 A 持有 lock1,并试图获取 lock2
  • 线程 B 持有 lock2,并试图获取 lock1

这时,A 等 B 释放 lock2,B 等 A 释放 lock1,形成循环等待,程序卡住——这就是典型的死锁。

示例:产生死锁的代码

立即学习Python免费学习笔记(深入)”;

import threading
import time
<p>lock1 = threading.Lock()
lock2 = threading.Lock()</p><p>def thread_1():
with lock1:
print("线程1 获取了 lock1")
time.sleep(1)
print("线程1 尝试获取 lock2")
with lock2:
print("线程1 获取了 lock2")</p><p>def thread_2():
with lock2:
print("线程2 获取了 lock2")
time.sleep(1)
print("线程2 尝试获取 lock1")
with lock1:
print("线程2 获取了 lock1")</p><p>t1 = threading.Thread(target=thread_1)
t2 = threading.Thread(target=thread_2)</p><p>t1.start()
t2.start()</p><p>t1.join()
t2.join()
登录后复制

运行这段代码,大概率会卡住,出现死锁。

如何避免死锁?使用递归锁 RLock

虽然 RLock(可重入锁)不能直接解决多锁交叉导致的死锁,但它允许同一个线程多次获取同一把锁,防止因重复加锁导致的自我阻塞。

更重要的是,避免死锁的关键是:保持加锁顺序一致

闪念贝壳
闪念贝壳

闪念贝壳是一款AI 驱动的智能语音笔记,随时随地用语音记录你的每一个想法。

闪念贝壳 218
查看详情 闪念贝壳

改进方案:统一加锁顺序 + 使用 RLock 防止重复加锁问题

import threading
import time
<h1>使用 RLock 替代 Lock,支持同一线程重复进入</h1><p>lock1 = threading.RLock()
lock2 = threading.RLock()</p><p>def worker_1():
print("线程1 开始")
with lock1:
print("线程1 获取 lock1")
time.sleep(0.5)
with lock2:  # 统一先 lock1 再 lock2
print("线程1 获取 lock2")</p><p>def worker_2():
print("线程2 开始")
with lock1:  # 同样先获取 lock1
print("线程2 获取 lock1")
time.sleep(0.5)
with lock2:
print("线程2 获取 lock2")</p><p>t1 = threading.Thread(target=worker_1)
t2 = threading.Thread(target=worker_2)</p><p>t1.start()
t2.start()</p><p>t1.join()
t2.join()
登录后复制

这个版本中,两个线程都按照 lock1 → lock2 的顺序加锁,避免了循环等待,从而防止死锁。

递归锁 RLock 的典型用途

当一个函数在持有锁的情况下调用另一个也需要同一把锁的函数时,普通 Lock 会导致阻塞,而 RLock 允许这种情况。

import threading
<p>rlock = threading.RLock()</p><p>def func1():
with rlock:
print("func1 已加锁")
func2()  # 调用另一个需要同样锁的函数</p><p>def func2():
with rlock:  # 同一线程可再次获取锁
print("func2 也获得了锁")</p><p>t = threading.Thread(target=func1)
t.start()
t.join()
登录后复制

如果这里用的是 Lock(),程序会在进入 func2 时被自己阻塞。

总结建议

  • 死锁主因是锁的获取顺序不一致或循环等待
  • 使用 threading.RLock 可解决同一线程重复加锁问题
  • 避免死锁的根本方法是:始终以相同顺序获取多个锁
  • 设计时尽量减少锁的数量和嵌套层级
  • 可以使用超时机制(acquire(timeout=))来检测潜在死锁

基本上就这些。掌握锁的使用顺序和选择合适的锁类型,能有效避免多线程中的死锁问题。

以上就是python多线程中的死锁和递归锁用法的详细内容,更多请关注php中文网其它相关文章!

python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号