介绍一种简单的避免死锁的加锁机制,并用Python实现和演示。

出现死锁的代码

死锁问题的出现往往是多线程情况下,每个线程需要一次性获取多个锁而导致的互相阻塞。例如考虑两个线程和两个锁的情况,线程一先获取锁一然后在获取锁二,而线程二先获取锁二再获取锁一,那么它们就可能出现互相等待对方释放锁而导致整个程序进入假死状态。

1
2
thread1 -> lock1 -> lock2
thread2 -> lock2 -> lock1

这样的死锁情况使用Python不难实现,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import threading
import time

lock1 = threading.Lock()
lock2 = threading.Lock()

def task(name, *locks):
for lock in locks:
print(name, "acquire", lock)
lock.acquire()
time.sleep(0.3)
print(name, "quit")

task1 = threading.Thread(target=task, args=("task1", lock1, lock2))
task2 = threading.Thread(target=task, args=("task2", lock2, lock1))

task1.start()
task2.start()

运行下来,程序因为死锁而无法退出,

1
2
3
4
5
$ python two_threads_locks.py 
task1 acquire <unlocked _thread.lock object at 0x7f0c5025f5a0>
task2 acquire <unlocked _thread.lock object at 0x7f0c502c3d80>
task1 acquire <locked _thread.lock object at 0x7f0c502c3d80>
task2 acquire <locked _thread.lock object at 0x7f0c5025f5a0>

死锁的解决方案:顺序加锁机制

以上代码可以看到,多线程下,如果锁的获取顺序不一致,就有可能出现死锁。既然如此,为程序中的每个锁分配唯一的id或编号,然后线程只允许按照锁编号的升序规则来获取多个锁。

转载请包括本文地址:https://allenwind.github.io/blog/10595
更多文章请参考:https://allenwind.github.io/blog/archives/