Python的线程16 一分钟写个死锁,单身狗谈何爱情

正式的Python专栏第53篇,同学站住,别错过这个从0开始的文章!

前面学委介绍Python的线程15 可重入锁RLock,文末提到了死锁。

所以这篇补充一下死锁的概念

死锁 是什么?

想象一下,身边有哪些无法解开的问题?

是不是有个问题想要跟对象讲道理,一开始好好聊,还能说明白。然后聊着聊着,对象反将一军:“你不够爱我了!(爱会消失。。。)”

搞的一下子懵了,本来是要讨论谁不该干嘛干嘛的事情,就陷入了僵局。

对,死锁就是这种感觉。

这里不一样的是,讨论问题从两个人,变成了两个线程/进程(或者更多,多个就类似你爸妈在讨论该不该生叉烧比较好还是你比较好,最后追溯到爷爷奶奶,祖祖辈辈牵扯整个家族的问题)

好,简单概括这种感觉就是:两个或者多个执行单元(线程/进程)请求受限资源碰到了僵局,争持不下。

特征上表现为:

一号线程持有锁A,继续执行的过程尝试获取锁B;
二号线程持有锁B,继续执行过程尝试获取锁A。

这样两个线程就是互相僵持,不让步,谁也没法让步。

就像下面的代码一样:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/11/24 12:02 上午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : testthread_lock_really_deadlock.py
# @Project : hello
import threading
import time

xuewei_account = 100
lock_01 = threading.Lock()
lock_02 = threading.Lock()


# amount为负数即是转出金额
def transfer1(money):
    print("%s - try to acquire lock_01" % threading.current_thread().name)
    lock_01.acquire()
    print("%s - acquired lock_01 transfer now" % threading.current_thread().name)
    time.sleep(3)
    print("%s - try to acquire lock_02" % threading.current_thread().name)
    lock_02.acquire()
    print("%s - acquired lock_02 transfer now" % threading.current_thread().name)
    print("transfer done")
    lock_02.release()
    lock_01.release()
    print("release")


# amount为负数即是转出金额
def transfer2(money):
    print("%s - try to acquire lock_02" % threading.current_thread().name)
    lock_02.acquire()
    print("%s - acquired lock_02 transfer now" % threading.current_thread().name)
    time.sleep(3)
    print("%s - try to acquire lock_01" % threading.current_thread().name)
    lock_01.acquire()
    print("%s - acquired lock_01 transfer now" % threading.current_thread().name)
    print("transfer done")
    lock_01.release()
    lock_02.release()
    print("release")


threading.Thread(name="这个线程%s要请求锁" % 1, target=lambda: transfer1(100)).start()
threading.Thread(name="这个线程%s要请求锁" % 2, target=lambda: transfer2(-100)).start()
print("-" * 16)
print("学委账户余额:", xuewei_account)

运行效果如下:

屏幕快照 2022-01-24 下午11.18.16.png

我们可以看到,两个线程一分别获取了lock_01和lock_02之后,

尝试获取lock_02 和 lock_01,然后就不继续运行了,没错,这就是死锁。

然而,主线程 则在一旁围观,他们锁了,没碍着主线程。主线程无欲无求,继续干着活,编写这代码,默默地输出xuewei_account余额。

总结

这篇小短文,简单介绍了一下死锁,展示了一下。

死锁是发生在两个线程之间的。

具体一点,这是死锁发生的4个必要条件:

  • 互斥条件:资源任意时刻只有一个持有者;仅当资源持有者释放,资源才可再次被申请
  • 不可剥夺条件:资源持有者保持锁的唯一话语权,持有者不释放资源,其他人只能干等
  • 请求与保持条件:资源申请者保持对已持有锁的锁定状态(吃碗看锅)
  • 循环等待条件:两个或者以上竞争者头尾相接等待资源,A->B->A如此循环等待

所以,一个线程如果发生了(代码不小心写了个死循环acquire同一个锁),那不算死锁(不满足学术定义)

简单理解可以是,”单身狗谈何爱情“,死锁是发生在两个或者更多资源竞争者之间的。

喜欢Python的朋友,请关注学委的 Python基础专栏 or Python入门到精通大专栏

持续学习持续开发,我是雷学委!
编程很有趣,关键是把技术搞透彻讲明白。
欢迎关注微信,点赞支持收藏!

猜你喜欢

转载自blog.csdn.net/geeklevin/article/details/123018397