关于 python 中死锁模拟的问题
Question about deadlock simulation in python
当我尝试实现一个python代码来模拟死锁时,我遇到了一些有趣的问题:
1)我用下面的代码来模拟死锁。
1 from threading import *
2 import time
3
4
5 def thread_one(lock1, lock2):
6 print("thread 1 is trying to acquire lock 1")
7 lock1.acquire()
8 print("lock1 acquired by thread 1")
9 time.sleep(1)
10 print("thread 1 is trying to acquire lock 2")
11 lock2.acquire()
12
13
14 def thread_two(lock1, lock2):
15 print("thread 2 is trying to acquire lock 2")
16 lock2.acquire()
17 print("lock2 acquired by thread 2")
18 time.sleep(1)
19 print("thread 2 is trying to acquire lock 1")
20 lock1.acquire()
21
22
23 if __name__ == "__main__":
24 lock1 = Lock()
25 lock2 = Lock()
26
27 t1 = Thread(target=thread_one, args=(lock1, lock2))
28 t2 = Thread(target=thread_two, args=(lock1, lock2))
29
30 t1.start()
31 t2.start()
32
33 t1.join()
34 t2.join()
这些是我的输出:
thread 1 is trying to acquire lock 1
lock1 acquired by thread 1
thread 2 is trying to acquire lock 2
lock2 acquired by thread 2
thread 1 is trying to acquire lock 2
thread 2 is trying to acquire lock 1
(program stuck here)
如有错误请指正。我认为我的模拟是正确的,两个线程卡在获取第二个锁的步骤。
2)然后我做了如下修改:
10 print("thread 1 is trying to release lock 2")
11 lock2.release()
28 t2 = Thread(target=thread_one, args=(lock1, lock2))
基本上,我希望两个线程实例都运行同一个函数thread_one并且在函数中它试图释放尚未获取的锁2。然后我得到了这些输出:
thread 1 is trying to acquire lock 1
lock1 acquired by thread 1
thread 1 is trying to acquire lock 1
thread 1 is trying to release lock 2
Exception in thread Thread-1:
Traceback (most recent call last):
File "/Users/bawang/.pyenv/versions/3.6.5/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/Users/bawang/.pyenv/versions/3.6.5/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "test.py", line 11, in thread_one
lock2.release()
RuntimeError: release unlocked lock
(program stuck here)
我的问题是:为什么两个线程都挂在那里(我需要按两次 ctrl+c 来取消它们)?我知道第二个线程正在等待第一个线程释放 lock1。但是,为什么第一个线程抛出异常后就卡住了呢?
3) 然后我通过进行以下更改进一步移动:
5 def thread_one(lock1, lock2):
6 print("thread 1 is trying to acquire lock 1")
7 lock1.acquire()
8 print("lock1 acquired by thread 1")
9 time.sleep(1)
10 print("thread 1 is trying to release lock 2")
11 lock2.release()
12
13
14 def thread_two(lock1, lock2):
15 print("thread 2 is trying to acquire lock 2")
16 lock2.acquire()
17 print("lock2 acquired by thread 2")
18 time.sleep(1)
19 print("thread 2 is trying to release lock 1")
20 lock1.release()
27 t1 = Thread(target=thread_one, args=(lock1, lock2))
28 t2 = Thread(target=thread_two, args=(lock1, lock2))
这次我想看看如果lock1&lock2被一个线程获取而另一个线程释放会发生什么。这些是我的输出:
thread 1 is trying to acquire lock 1
lock1 acquired by thread 1
thread 2 is trying to acquire lock 2
lock2 acquired by thread 2
thread 1 is trying to release lock 2
thread 2 is trying to release lock 1
(Program completes)
我的问题是为什么没有例外?在这种情况下,我确实期望有两个 RuntimeError: release unlocked lock。
1) 是的。你是对的。
2) 如您所料,第一个线程已停止,但您还有两个线程:第二个线程和主线程。第一个 cntl + c 杀死主线程。您可以查看 KeybboardInterrupt
的消息。第一个发生在 t2.join()
.
3) 两个线程都正确获取和释放。不同的线程可以获得同一个锁。因此,线程1只是释放了线程2获得的锁2,反之亦然。
您的代码的执行顺序没有保证,因此线程 1 可能会在线程 2 获取锁 2 之前释放锁 2。但是您可以再次 运行 代码,线程 2 可以在线程 1 然后释放它之前获取它。我不确定您在示例中途尝试实现的目标。
最后一个例子没有产生任何异常的原因应该从输出中很清楚:
thread 1 is trying to acquire lock 1
lock1 acquired by thread 1
thread 2 is trying to acquire lock 2
lock2 acquired by thread 2
thread 1 is trying to release lock 2
thread 2 is trying to release lock 1
线程尝试做的所有事情,它们都会成功。由于您将相同的锁传递给两个线程,因此没有理由线程 1 无法获取锁 1 然后线程 2 释放它,而线程 2 获取锁 2 然后线程 1 释放它 -程序可以成功完成。
由于 sleep(1)
,您几乎可以保证获得该输出,尽管不完全是 - 如果某些东西阻止线程 2 在一秒钟内启动,线程 1 可能仍会尝试释放锁 2 之前收购 - 依靠超时不是一种安全的编码方式。
当我尝试实现一个python代码来模拟死锁时,我遇到了一些有趣的问题:
1)我用下面的代码来模拟死锁。
1 from threading import *
2 import time
3
4
5 def thread_one(lock1, lock2):
6 print("thread 1 is trying to acquire lock 1")
7 lock1.acquire()
8 print("lock1 acquired by thread 1")
9 time.sleep(1)
10 print("thread 1 is trying to acquire lock 2")
11 lock2.acquire()
12
13
14 def thread_two(lock1, lock2):
15 print("thread 2 is trying to acquire lock 2")
16 lock2.acquire()
17 print("lock2 acquired by thread 2")
18 time.sleep(1)
19 print("thread 2 is trying to acquire lock 1")
20 lock1.acquire()
21
22
23 if __name__ == "__main__":
24 lock1 = Lock()
25 lock2 = Lock()
26
27 t1 = Thread(target=thread_one, args=(lock1, lock2))
28 t2 = Thread(target=thread_two, args=(lock1, lock2))
29
30 t1.start()
31 t2.start()
32
33 t1.join()
34 t2.join()
这些是我的输出:
thread 1 is trying to acquire lock 1
lock1 acquired by thread 1
thread 2 is trying to acquire lock 2
lock2 acquired by thread 2
thread 1 is trying to acquire lock 2
thread 2 is trying to acquire lock 1
(program stuck here)
如有错误请指正。我认为我的模拟是正确的,两个线程卡在获取第二个锁的步骤。
2)然后我做了如下修改:
10 print("thread 1 is trying to release lock 2")
11 lock2.release()
28 t2 = Thread(target=thread_one, args=(lock1, lock2))
基本上,我希望两个线程实例都运行同一个函数thread_one并且在函数中它试图释放尚未获取的锁2。然后我得到了这些输出:
thread 1 is trying to acquire lock 1
lock1 acquired by thread 1
thread 1 is trying to acquire lock 1
thread 1 is trying to release lock 2
Exception in thread Thread-1:
Traceback (most recent call last):
File "/Users/bawang/.pyenv/versions/3.6.5/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/Users/bawang/.pyenv/versions/3.6.5/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "test.py", line 11, in thread_one
lock2.release()
RuntimeError: release unlocked lock
(program stuck here)
我的问题是:为什么两个线程都挂在那里(我需要按两次 ctrl+c 来取消它们)?我知道第二个线程正在等待第一个线程释放 lock1。但是,为什么第一个线程抛出异常后就卡住了呢?
3) 然后我通过进行以下更改进一步移动:
5 def thread_one(lock1, lock2):
6 print("thread 1 is trying to acquire lock 1")
7 lock1.acquire()
8 print("lock1 acquired by thread 1")
9 time.sleep(1)
10 print("thread 1 is trying to release lock 2")
11 lock2.release()
12
13
14 def thread_two(lock1, lock2):
15 print("thread 2 is trying to acquire lock 2")
16 lock2.acquire()
17 print("lock2 acquired by thread 2")
18 time.sleep(1)
19 print("thread 2 is trying to release lock 1")
20 lock1.release()
27 t1 = Thread(target=thread_one, args=(lock1, lock2))
28 t2 = Thread(target=thread_two, args=(lock1, lock2))
这次我想看看如果lock1&lock2被一个线程获取而另一个线程释放会发生什么。这些是我的输出:
thread 1 is trying to acquire lock 1
lock1 acquired by thread 1
thread 2 is trying to acquire lock 2
lock2 acquired by thread 2
thread 1 is trying to release lock 2
thread 2 is trying to release lock 1
(Program completes)
我的问题是为什么没有例外?在这种情况下,我确实期望有两个 RuntimeError: release unlocked lock。
1) 是的。你是对的。
2) 如您所料,第一个线程已停止,但您还有两个线程:第二个线程和主线程。第一个 cntl + c 杀死主线程。您可以查看 KeybboardInterrupt
的消息。第一个发生在 t2.join()
.
3) 两个线程都正确获取和释放。不同的线程可以获得同一个锁。因此,线程1只是释放了线程2获得的锁2,反之亦然。
您的代码的执行顺序没有保证,因此线程 1 可能会在线程 2 获取锁 2 之前释放锁 2。但是您可以再次 运行 代码,线程 2 可以在线程 1 然后释放它之前获取它。我不确定您在示例中途尝试实现的目标。
最后一个例子没有产生任何异常的原因应该从输出中很清楚:
thread 1 is trying to acquire lock 1
lock1 acquired by thread 1
thread 2 is trying to acquire lock 2
lock2 acquired by thread 2
thread 1 is trying to release lock 2
thread 2 is trying to release lock 1
线程尝试做的所有事情,它们都会成功。由于您将相同的锁传递给两个线程,因此没有理由线程 1 无法获取锁 1 然后线程 2 释放它,而线程 2 获取锁 2 然后线程 1 释放它 -程序可以成功完成。
由于 sleep(1)
,您几乎可以保证获得该输出,尽管不完全是 - 如果某些东西阻止线程 2 在一秒钟内启动,线程 1 可能仍会尝试释放锁 2 之前收购 - 依靠超时不是一种安全的编码方式。