寻找僵局


18

寻找僵局

对多线程应用程序进行编程时,必须格外小心,以避免在访问共享资源时死锁各个线程。一个死锁发生时线程试图访问要锁定在另一个线程在同一时间,其他线程试图访问由第一锁定的资源的资源。这是简单的情况,但是如果资源链较长,则可能变得更加复杂。

挑战

您应该编写一个程序或函数,以在每个线程访问的资源列表中检测可能的死锁情况。这是代码高尔夫球,因此最短答案以字节为单位。

每个线程是同时启动的,但是之后它们可以按交错的任意组合运行。如果有2个线程,每个4个动作,它可以作为运行(其中,每个数字是具有该ID采取的线程的动作)1,1,1,1,2,2,2,22,2,2,2,1,1,1,11,2,1,2,1,2,1,21,1,2,2,2,2,1,1,或任何其它可能的组合。

输入值

您将通过STDIN,函数参数或最接近的替代方法接收字符串列表。每个字符串将采用格式+a -b。该字符串中的每个字符串都表示线程对资源的locking(+)/ unlocking(-)。每个线程之间将有一个---分隔符。确保线程不会尝试锁定已锁定的资源,并且所有线程将在退出前显式解锁其锁定的所有资源。下面是一个示例来演示:

+a    # Lock resource a
+b    # Lock resource b
-a    # Unlock resource a
-b    # Unlock resource b
---   # Thread separator
+b    # Lock resource b
-b    # Unlock resource b

输出量

如果输入不包含任何可能的死锁,则输出为假,如果输入包含可能的死锁情况,则输出为假。例如:

  • true
  • false
  • 1
  • 0

都是有效的输出,但是任何明确定义为“真/假”的内容都可以接受。

例子

+a
-a
---
+a
-a

输出: false


+a
+b
-b
-a
---
+b
+a
-a
-b

输出量 true

尝试b,a分别获取线程时出现死锁1,2


+a
+b
-a
-b
---
+a
+b
-b
-a

输出量 false


+a
+b
-b
-a
---
+b
+c
-c
-b
---
+c
+a
-a
-c

输出: true

尝试b,c,a分别获取线程1,2,3中的死锁。


http://pastebin.com/vMYRZxtW

输出量 false


http://pastebin.com/V5MVgNgS

输出量 true

b,d,a分别尝试获取时,线程1、2、3死锁。


当然,这可能变得更加复杂,具有更多的线程,每个线程都有更多的资源,依此类推,但是我相信这些测试涵盖了基础知识。

奖金

由于编写程序时遇到死锁情况非常令人难过,因此答案输出:(:)真/假分别有-8个字节的奖励。


我只是在假设这一点,但是很高兴澄清每个线程的操作(从线程顶部开始)是并行运行的并且对应于相同的系统时间
Optimizer

1
这些动作可以同时运行,但是不能假定每个动作的运行时间。可能发生的是,线程实际上严格地一个接一个地运行,或者完全交织。可能是线程1的前一半运行了,然后线程2完全运行了,然后线程1运行了它的后一半。等等。我已经更新了问题以澄清这一点。
rorlork 2015年

1
好的,所以任务是弄清楚给定线程运行时间的任何可能组合,是否可能发生死锁。
Optimizer

是的,对不起,我认为这不会引起怀疑。实际上,在最后一个示例中,由于线程2 d直到稍后才尝试使用资源,因此对此进行了演示。
rorlork 2015年

1
@rcrmn您确定:)不应该为假或:(为真吗?
蒂洛

Answers:


4

Python 2-227

基本上确保没有“优先级”循环。例如,在第二个测试中,第一个线程具有a(b)优先级,第二个线程具有b(a)优先级。

我当时正在考虑用Pyth重写它,因为我认为它可以与所有itertools操作一起很好地工作,但是转换正则表达式将需要一些工作,因此现在我将发布它,并尝试将其转换并稍后发布另一个答案。

from itertools import*
import re
f=lambda t:any(re.search(r"(.)((.)\3)+\1",''.join(p))for i in product(*[[m.group(1)+m.group(2)for m in re.finditer(r"(\w).*(\w).*\2.*\1",e,16)]for e in t.split('---')])for p in permutations(i))


@Tyilo它为我输出True;您运行得如何?
KSab 2015年

哦,只为我读一行。您应该如何运行它?
蒂洛2015年

@Tyilo我将格式更改为以多行字符串作为输入的函数
KSab 2015年

5

蟒- 586 539 524 501 485字节- 8 = 477

缩进级别:

1: 1 space
2: 1 tab
3: 1 tab + 1 space
4: 2 tabs

-

import sys
V=set()
t=[[[]]]
for r in sys.stdin:
 r=r.strip()
 if'---'==r:t.append([[]])
 else:v=r[1:];V.add(v);l=t[-1][-1];t[-1].append(l+[v]if'+'==r[0]else filter(lambda x:x!=v,l))
s=lambda l:s(l[1:])+map(lambda x:(l[0],x),l[1:])if 1<len(l)else[]
E=reduce(set.union,map(lambda x:set(sum(map(s,x),[])),t),set())
for v in V:
 k=set();q=[v]
 while 0<len(q):
    u=q.pop(0)
    if u in k:continue
    k.add(u)
    for x,y in E:
     if u==x:
        if y in k:print':(';sys.exit()
        else:q.append(y)
print':)'

1
使用;结合被缩进保存字符的行。同样,使您的陈述成为衬板。
isaacg 2015年

@isaacg和ace,谢谢!我想我会尽力使用您的技巧来改善它。
蒂洛

顺便说一句,如果您不介意管道输入文件(或按Ctrl + D两次),则可以for r in sys.stdin代替for r in sys.stdin.readlines()
user12205

@ace我看到使用just sys.stdin或之间没有任何不同的行为sys.stdin.readlines(),所以我更改了它,再次感谢。
蒂洛

您可以删除之间的空间print':)'
user12205
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.