python基础-死锁、递归锁

死锁

所谓死锁: 是指两个或两个以上的进程或线程在执行过程当中,因争夺资源而形成的一种互相等待的现象,若无外力做用,它们都将没法推动下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程python

from threading import Thread,Lock
import time
mutexA=Lock()
mutexB=Lock()

class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()
    def func1(self):
        mutexA.acquire()
        print('\033[41m%s 拿到A锁\033[0m' %self.name)

        mutexB.acquire()
        print('\033[42m%s 拿到B锁\033[0m' %self.name)
        mutexB.release()

        mutexA.release()

    def func2(self):
        mutexB.acquire()
        print('\033[43m%s 拿到B锁\033[0m' %self.name)
        time.sleep(2)

        mutexA.acquire()
        print('\033[44m%s 拿到A锁\033[0m' %self.name)
        mutexA.release()

        mutexB.release()

if __name__ == '__main__':
    for i in range(5):
        t=MyThread()
        t.start()

输出以下:web

Thread-1 拿到A锁
Thread-1 拿到B锁
Thread-1 拿到B锁
Thread-2 拿到A锁

分析如上代码是如何产生死锁的:
启动5个线程,执行run方法,假如thread1首先抢到了A锁,此时thread1没有释放A锁,紧接着执行代码mutexB.acquire(),抢到了B锁,在抢B锁时候,没有其余线程与thread1争抢,由于A锁没有释放,其余线程只能等待,而后A锁就执行完func1代码,而后继续执行func2代码,与之同时,在func2中,执行代码 mutexB.acquire(),抢到了B锁,而后进入睡眠状态,在thread1执行完func1函数,释放AB锁时候,其余剩余的线程也开始抢A锁,执行func1代码,若是thread2抢到了A锁,接下来thread2要抢B锁,ok,在这个时间段,thread1已经执行func2抢到了B锁,而后在sleep(2),持有B锁没有释放,为何没有释放,由于没有其余的线程与之争抢,他只能睡着,而后thread1握着B锁,thread2要抢B锁,ok,这样就造成了死锁svg

递归锁

咱们分析了死锁,那么python里面是如何解决这样的递归锁呢?
在Python中为了支持在同一线程中屡次请求同一资源,python提供了可重入锁RLock。函数

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源能够被屡次require。直到一个线程全部的acquire都被release,其余的线程才能得到资源。上面的例子若是使用RLock代替Lock,则不会发生死锁:ui

from threading import Thread,Lock,RLock
import time

mutexA=mutexB=RLock()


class MyThread(Thread):
    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print('%s 拿到A锁' %self.name)

        mutexB.acquire()
        print('%s 拿到B锁' %self.name)
        mutexB.release()

        mutexA.release()

    def f2(self):
        mutexB.acquire()
        print('%s 拿到B锁' % self.name)
        time.sleep(0.1)
        mutexA.acquire()
        print('%s 拿到A锁' % self.name)
        mutexA.release()

        mutexB.release()


if __name__ == '__main__':
    for i in range(5):
        t=MyThread()
        t.start()

输出代码以下:spa

E:\python\python_sdk\python.exe "E:/python/py_pro/3 死锁现象与递归锁.py"
Thread-1 拿到A锁
Thread-1 拿到B锁
Thread-1 拿到B锁
Thread-1 拿到A锁
Thread-2 拿到A锁
Thread-2 拿到B锁
Thread-2 拿到B锁
Thread-2 拿到A锁
Thread-4 拿到A锁
Thread-4 拿到B锁
Thread-4 拿到B锁
Thread-4 拿到A锁
Thread-3 拿到A锁
Thread-3 拿到B锁
Thread-3 拿到B锁
Thread-3 拿到A锁
Thread-5 拿到A锁
Thread-5 拿到B锁
Thread-5 拿到B锁
Thread-5 拿到A锁

Process finished with exit code 0

或者以下的效果:
这里写图片描述线程

来解释下递归锁的代码:
因为锁A,B是同一个递归锁,thread1拿到A,B锁,counter记录了acquire的次数2次,而后在func1执行完毕,就释放递归锁,在thread1释放完递归锁,执行完func1代码,接下来会有2种可能,一、thread1在次抢到递归锁,执行func2代码 二、其余的线程抢到递归锁,去执行func1的任务代码code