0

0

Python死锁如何产生_锁顺序问题

冰川箭仙

冰川箭仙

发布时间:2026-03-09 20:06:35

|

796人浏览过

|

来源于php中文网

原创

锁顺序问题是python死锁最常见原因,指多个线程以不一致顺序获取同一组锁(如线程1先a后b、线程2先b后a),导致互相等待永久阻塞。

python死锁如何产生_锁顺序问题

Python中死锁最常见原因之一是多个线程以不同顺序获取多个锁,导致互相等待——即“锁顺序问题”。只要两个或以上线程对同一组锁的加锁顺序不一致,就可能陷入永久阻塞。

什么是锁顺序问题

假设有两个锁 lock_Alock_B。线程1先获取 lock_A,再尝试获取 lock_B;而线程2恰好相反:先获取 lock_B,再尝试获取 lock_A。当线程1拿到 lock_A、线程2拿到 lock_B 后,两者都会卡在第二个锁上,谁也无法继续,形成死锁。

典型触发场景

  • 多个函数各自独立加锁,但未约定全局加锁顺序(例如:函数A按 A→B 加锁,函数B按 B→A 加锁)
  • 嵌套调用时,底层函数悄悄加了新锁,调用方 unaware,无意中改变了锁序
  • 使用可重入锁(RLock)误以为安全,但跨锁协作时仍需严格顺序
  • 分布式或模拟多资源场景(如转账:账户A扣款→账户B入账),资源顺序不统一

如何避免锁顺序问题

  • 固定全局锁顺序:对所有涉及的锁定义唯一编号或排序规则(如按锁对象 id()、变量名字符串排序),始终按升序(或降序)获取
  • 一次性申请所有锁:用 threading.Lockacquire(timeout=...) 配合循环重试,或使用 contextlib.ExitStack 管理多锁,但更推荐用 concurrent.futures.ThreadPoolExecutor 减少手动锁需求
  • 避免嵌套加锁:设计函数时明确是否持有锁;若必须嵌套,确保被调函数不引入新锁,或由最外层统一管理
  • 用超时机制兜底:给 lock.acquire(timeout=0.5) 设置合理超时,失败后释放已持锁并重试/报错,防止无限等待

一个可复现的死锁示例

以下代码会大概率触发死锁:

import threading
import time
<p>lock_a = threading.Lock()
lock_b = threading.Lock()</p><p>def thread1():
with lock_a:
time.sleep(0.1)
with lock_b:  # 等待 lock_b
print("Thread1 done")</p><p>def thread2():
with lock_b:
time.sleep(0.1)
with lock_a:  # 等待 lock_a
print("Thread2 done")</p><p>t1 = threading.Thread(target=thread1)
t2 = threading.Thread(target=thread2)
t1.start(); t2.start()
t1.join(); t2.join()</p>

运行后程序常卡住不动——因为 thread1 持有 lock_a 等 lock_b,thread2 持有 lock_b 等 lock_a,双方僵持。

Colossyan
Colossyan

AI虚拟人出镜视频生成

下载

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

修复思路很简单

强制统一顺序:比如规定所有地方都先 lock_a 再 lock_b。修改任一函数即可打破循环依赖:

def thread2_fixed():
    with lock_a:  # 先 a
        with lock_b:  # 再 b
            print("Thread2 fixed")

或者更健壮地用排序逻辑自动保证顺序,适合锁数量多、来源动态的场景。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

404

2023.08.11

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

250

2023.10.07

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

739

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

220

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1564

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

649

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1188

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

1184

2024.04.29

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

59

2026.03.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 4.9万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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