死锁的原因及解决办法

死锁

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

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

如下代码:

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是一个钥匙串的很多把钥匙,每个钥匙都可以开一把锁,但是只要一个进程拿到这串钥匙的其中一个钥匙,其他线程就拿不到钥匙了,这就是递归锁,就造成不了面条和筷子分别被两个线程拿到的情况了。

结束!

 

你可能感兴趣的:(死锁的原因及解决办法)