zoukankan      html  css  js  c++  java
  • 死锁的原因及解决办法RLock递归锁

    死锁

    说到死锁,可以讲一个科学家吃面的问题:

    有几个科学家在一张桌子旁,桌子上只有一把筷子和一碗面,我们将面和筷子都加锁。这是可能会导致一个科学家抢到面,另一个科学家抢到筷子,这是就全部阻塞了,这就是死锁了。

    如下代码:

    from threading import Thread, Lock, RLock
    import time
    
    # 这个函数,先让拿筷子,再拿面条,
    def eat1(args, Chopsticks_lock, Noodles_lock):
        Chopsticks_lock.acquire()  # 拿钥匙
        print('%s拿到了筷子'%args)
        Noodles_lock.acquire()  # 拿钥匙
        print('%s拿到了面条'%args)
        print('%s吃到了面条'%args)
        Noodles_lock.release()  # 还钥匙
        Chopsticks_lock.release()  # 还钥匙
    
    # 这个函数,先让那面条,再让拿筷子。
    def eat2(args, Chopsticks_lock, Noodles_lock):
        Noodles_lock.acquire()
        print('%s拿到了面条' % args)
        time.sleep(0.1)  # 让睡0.1面,这样更容易,一个线程拿到面条,一个线程拿到筷子,出现阻塞,出现死锁。
        Chopsticks_lock.acquire()
        print('%s拿到了筷子'%args)
        print('%s吃到了面条'%args)
        Noodles_lock.release()
        Chopsticks_lock.release()
        
    # 创建两个锁,分别给面条和筷子加锁。
    Chopsticks_lock = Lock()
    Noodles_lock = Lock()
    Thread(target=eat1, args=('小明', Chopsticks_lock, Noodles_lock)).start()
    Thread(target=eat2, args=('小红', Chopsticks_lock, Noodles_lock)).start()
    Thread(target=eat1, args=('小兰', Chopsticks_lock, Noodles_lock)).start()
    Thread(target=eat2, args=('小军', Chopsticks_lock, Noodles_lock)).start()

    打印结果:

    小明拿到了筷子
    小明拿到了面条
    小明吃到了面条
    小红拿到了面条
    小兰拿到了筷子

    看到小红拿到了面条,而小兰拿到了筷子,他们都需要对方拿到的资源来完成吃面条的整个过程,但是线程未使用完资源之前,不可被剥夺,并且线程拿不到需要的资源就会阻塞,就造成了死锁的情况。

    如何解决?

    引入递归锁。

    递归锁RLock

    from threading import Thread, Lock, RLock
    import time
    
    
    def eat1(args, Chopsticks_lock, Noodles_lock):
        Chopsticks_lock.acquire()
        print('%s拿到了筷子'%args)
        Noodles_lock.acquire()
        print('%s拿到了面条'%args)
        print('%s吃到了面条'%args)
        Noodles_lock.release()
        Chopsticks_lock.release()
    
    
    def eat2(args, Chopsticks_lock, Noodles_lock):
        Noodles_lock.acquire()
        print('%s拿到了面条' % args)
        time.sleep(0.1)
        Chopsticks_lock.acquire()
        print('%s拿到了筷子'%args)
        print('%s吃到了面条'%args)
        Noodles_lock.release()
        Chopsticks_lock.release()
    
    
    Chopsticks_lock = Noodles_lock = RLock()
    
    Thread(target=eat1, args=('小明', Chopsticks_lock, Noodles_lock)).start()
    Thread(target=eat2, args=('小红', Chopsticks_lock, Noodles_lock)).start()
    Thread(target=eat1, args=('小兰', Chopsticks_lock, Noodles_lock)).start()
    Thread(target=eat2, args=('小军', Chopsticks_lock, Noodles_lock)).start()

    打印结果:

    小明拿到了筷子
    小明拿到了面条
    小明吃到了面条
    小红拿到了面条
    小红拿到了筷子
    小红吃到了面条
    小兰拿到了筷子
    小兰拿到了面条
    小兰吃到了面条
    小军拿到了面条
    小军拿到了筷子
    小军吃到了面条

    值得注意的是,线程锁Lock是互斥锁,只有一把钥匙。而递归锁RLock是一个钥匙串的很多把钥匙,每个钥匙都可以开一把锁,但是只要一个进程拿到这串钥匙的其中一个钥匙,其他线程就拿不到钥匙了,这就是递归锁,就造成不了面条和筷子分别被两个线程拿到的情况了。

    结束!

  • 相关阅读:
    JavaScript : 零基础打造自己的类库
    Basler和Matrox的配置及调试
    StanFord ML 笔记 第十部分
    StanFord ML 笔记 第九部分
    凸优化&非凸优化问题
    一些误差的概念
    StanFord ML 笔记 第八部分
    StanFord ML 笔记 第六部分&&第七部分
    StanFord ML 笔记 第五部分
    大数定律和中心极限定律
  • 原文地址:https://www.cnblogs.com/aaronthon/p/9852751.html
Copyright © 2011-2022 走看看