💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] **多进程好多线程都有死锁的问题** ## 一 死锁现象 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程, ### 死锁案例-科学家吃面问题 ~~~ import time from threading import Thread,Lock def eat1(name,fork_lock,noodle_lock): fork_lock.acquire() #拿叉子锁 print('%s拿到叉子了'%name) noodle_lock.acquire() #拿面条锁 print('%s拿到面条了' % name) print('%s吃面'%name) noodle_lock.release() #释放面条锁 fork_lock.release() #释放叉子锁 def eat2(name,fork_lock,noodle_lock): noodle_lock.acquire() print('%s拿到面条了' % name) time.sleep(1) fork_lock.acquire() print('%s拿到叉子了' % name) print('%s吃面'%name) fork_lock.release() noodle_lock.release() fork_lock = Lock() noodle_lock = Lock() Thread(target=eat1,args=('alex',fork_lock,noodle_lock)).start() Thread(target=eat2,args=('wusir',fork_lock,noodle_lock)).start() ~~~ **执行效果** ~~~ alex拿到叉子了 alex拿到面条了 alex吃面 wusir拿到面条了 yuan拿到叉子了 #出现死锁,整个程序阻塞住 ~~~ ## 二 递归锁 解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。 这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。 ### 递归锁解决吃面问题 ~~~ import time from threading import Thread,RLock def eat1(name,fork_lock,noodle_lock): fork_lock.acquire() print('%s拿到叉子了'%name) noodle_lock.acquire() print('%s拿到面条了' % name) print('%s吃面'%name) noodle_lock.release() fork_lock.release() def eat2(name,fork_lock,noodle_lock): noodle_lock.acquire() print('%s拿到面条了' % name) time.sleep(1) fork_lock.acquire() print('%s拿到叉子了' % name) print('%s吃面'%name) fork_lock.release() noodle_lock.release() fork_lock =noodle_lock = RLock() #一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1, #这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止 Thread(target=eat1,args=('alex',fork_lock,noodle_lock)).start() Thread(target=eat2,args=('wusir',fork_lock,noodle_lock)).start() Thread(target=eat1,args=('yuan',fork_lock,noodle_lock)).start() ~~~ 执行结果: ``` alex拿到叉子了 alex拿到面条了 alex吃面 wusir拿到面条了 wusir拿到叉子了 wusir吃面 yuan拿到叉子了 yuan拿到面条了 yuan吃面 Process finished with exit code 0 ``` ## 互斥锁和递归锁的区别 互斥锁在同一个线程中连续acquire一次以上就会死锁 递归锁在同一个线程中可以连续的acquire多次而不发生死锁 * 普遍说法 : 递归锁可以代替互斥锁来解决死锁现象 * 实际上 : 递归锁的解决死锁实际上是牺牲了时间和空间的 **死锁从本质上来讲是一种逻辑错** **递归锁没有从根本上解决死锁问题**