python 并发编程 多线程 死锁现象与递归锁

Posted mingerlcm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 并发编程 多线程 死锁现象与递归锁相关的知识,希望对你有一定的参考价值。

 

 

一 死锁现象

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

from threading import Thread
from threading import Lock
import time

# 实例化两把不同的锁
mutexA = Lock()
mutexB = Lock()

class MyThread(Thread):

    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print("%s拿到A锁" % self.name)  # Thread类自带name属性

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

        mutexA.release()

    def f2(self):
        mutexB.acquire()
        print("%s拿到B锁" % self.name)  # Thread类自带name属性
        time.sleep(0.1)
        mutexA.acquire()

        print("%s拿到A锁" % self.name)
        mutexA.release()

        mutexB.release()

if __name__ == "__main__":
    for i in range(1,11):
        t = MyThread()
        t.start()

执行结果

Thread-1拿到A锁
Thread-1拿到B锁
Thread-1拿到B锁
Thread-2拿到A锁 # 出现死锁,整个程序卡住

 

解决方法:

二 递归锁

递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。

 

上面的例子如果使用RLock代替Lock,则不会发生死锁,

二者的区别是:

递归锁可以连续acquire多次,每acquire一次计数器加1,

只要计数不为0,就不能被其他线程抢到。只有计数为0时,才能被其他线程抢到acquire。释放一次计数器-1

而互斥锁只能加锁acquire一次,想要再加锁acquire,就需要release解之前的锁

from threading import Thread
from threading import RLock
import time

# 实例化一把锁,mutexA 和mutexB公用一把锁
mutexB = mutexA = RLock()

class MyThread(Thread):

    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print("%s拿到A锁" % self.name)  # Thread类自带name属性

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

        mutexA.release()

    def f2(self):
        mutexB.acquire()
        print("%s拿到B锁" % self.name)  # Thread类自带name属性
        time.sleep(0.1)
        mutexA.acquire()

        print("%s拿到A锁" % self.name)
        mutexA.release()

        mutexB.release()

if __name__ == "__main__":
    for i in range(1,5):
        t = MyThread()
        t.start()
‘‘‘
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锁
‘‘‘

 

 

以上是关于python 并发编程 多线程 死锁现象与递归锁的主要内容,如果未能解决你的问题,请参考以下文章

百万年薪python之路 -- 并发编程之 多线程 二

Python并发编程05/ 死锁/递归锁/信号量/GIL锁/进程池/线程池

day10-python并发编程之多线程协程及MySQL

python并发编程之线程(创建线程,锁(死锁现象,递归锁),GIL锁)

Python——并发编程02

python-day36--并发编程之多线程