假设这是事件的实际顺序,那里没有死锁。最初,所有资源都是免费的,按顺序运行该代码:
1. P1 requests R2: p1 has r2.
2. P4 requests R3: p4 has r3.
3. P3 requests R1: p3 has r1.
4. P2 requests R4: p2 has r4.
5. P5 requests R5: p5 has r5.
6. P4 requests R2: p4 has r3, awaiting r2(p1).
7. P5 requests R3: p5 has r5, awaiting r3(p4).
8. P3 requests R5: p3 has r1, awaiting r5(p5).
所以目前的状态是:
p1 has r2.
p2 has r4.
p3 has r1, awaiting r5(p5).
p4 has r3, awaiting r2(p1).
p5 has r5, awaiting r3(p4).
等待链是(服务员->拦截器):
p4 -> p1, p5 -> p4, p3 -> p5
或者:
p3 -> p5 -> p4 -> p1
因为那里没有循环,所以没有发生死锁。
通过简单地让非服务员释放他们的资源并遵循事件链可以获得进一步的证明:
9. p1 releases r2, frees it up for p4 (p3 and p5 blocked, p4 has r3/r2).
10. p4 releases r3, frees it up for p5 (p3 blocked, p5 has r5/r3).
11. p5 releases r5, frees it up for p3 (nobody is blocked, p3 has r5).
这些步骤之后的最终状态是:
p1 has nothing.
p2 has r4.
p3 has r1/r5.
p4 has r2.
p5 has r3.
现在没有阻塞,每个线程都可以简单地释放它们仍然分配的任何资源。
现在,如果您扩展您的问题以询问如果这些操作可以按任何顺序发生(同时保持每个线程内的顺序)是否可能发生死锁,答案仍然是否定的。
这是多线程的基本原则,您可以通过确保所有资源在每个线程中以相同的顺序分配来避免死锁。根据您提供的操作,各个线程按如下方式分配其资源(必须在线程内维护顺序):
P1: R2
P2: R4
P3: R1 R5
P4: R3 R2
P5: R5 R3
那么,我们如何确保它们都以相同的顺序分配呢?我们只需要找到一个匹配的序列。首先,我们从上面的列表开始,但添加空格,以便排列相似的资源并且没有资源位于另一个资源的两侧:
P1: R2
P2: R4
P3: R1 R5
P4: R3 R2
P5: R5 R3
R4 R1 R5 R3 R2 <==
还有你的序列。每个线程都按 4、1、5、3、2 的顺序分配资源。并非每个线程都分配所有资源,但这在这里无关紧要。
这也不是唯一的解决方案(R4 是独立的,因此它可以放在列表中的任何位置 - 每个其他资源都包含在单个依赖链(1、5、3、2)中,因此它们的相对位置是固定的)。
但是,只要证明每个线程都按特定顺序分配资源就足够了,因此死锁是不可能的。