Нахождение тупика

18

Нахождение тупика

При программировании многопоточного приложения необходимо соблюдать осторожность, чтобы избежать блокировки различных потоков при доступе к общим ресурсам. Тупиковый происходит , когда поток пытается получить доступ к ресурсу , который заперт в другом потоке , в то же время, другой поток пытается получить доступ к ресурсу блокируется первым. Это простой случай, но он может стать более сложным с более длинными цепочками ресурсов.

Соревнование

Вы должны написать программу или функцию, которая может обнаружить возможную ситуацию взаимоблокировки в списке ресурсов, к которым обращается каждый поток. Это код-гольф, поэтому выигрывает самый короткий ответ в байтах.

Все потоки запускаются одновременно, но после этого они могут работать при любом сочетании чередования. Если есть 2 нити с 4 -х действиях каждого, она может быть запущена как (где каждое число представляет собой действие , предпринимаемое нити с этим идентификатором) 1,1,1,1,2,2,2,2, 2,2,2,2,1,1,1,1, 1,2,1,2,1,2,1,2, 1,1,2,2,2,2,1,1, или любой другой возможной комбинацией.

вход

Вы получите через STDIN, параметр функции или ближайшую альтернативу, список строк. Каждая строка будет в формате +a -b. Каждая из этих строк представляет блокировку ( +) / разблокировку ( -) ресурса потоком. Между каждым потоком будет ---разделитель. Гарантируется, что поток не будет пытаться заблокировать ресурс, который он уже заблокировал, и что все потоки будут явно разблокировать все ресурсы, которые они заблокировали перед выходом. Ниже приведен пример для демонстрации:

+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

Тупик в темах 1,2,3 при попытке приобрести b,c,aсоответственно.


http://pastebin.com/vMYRZxtW

Выход false


http://pastebin.com/V5MVgNgS

Выход true

Тупик в темах 1,2,3 при попытке добыть b,d,aсоответственно.


Конечно, это может быть намного сложнее, с большим количеством потоков, большим количеством ресурсов для каждого и так далее, но я считаю, что эти тесты охватывают основы.

бонус

Так как это очень и очень печально, когда вы находите тупиковые ситуации при написании программы, есть бонус -8 байт к выводу ответов :(и :)как к правде / ложности соответственно.

rorlork
источник
Я просто предполагаю это, но было бы неплохо уточнить, что действия каждого потока (начиная с верха потока) выполняются параллельно и соответствуют одному и тому же системному времени
Оптимизатор
1
Действия выполняются одновременно, но нельзя предположить время, в которое выполняется каждое действие. Может случиться так, что потоки на самом деле работают строго один за другим или полностью чередуются. Может быть так, что первая половина потока 1 выполняется, затем поток 2 выполняется полностью, а затем поток 1 выполняет свою вторую половину. И так далее. Я обновил вопрос, чтобы уточнить это.
rorlork
1
Ах, хорошо, поэтому задача состоит в том, чтобы выяснить, возможна ли тупиковая ситуация при любой возможной комбинации времен выполнения потоков.
Оптимизатор
Да, извините, я не думал, что это может оставить сомнения. На самом деле в последнем примере это продемонстрировано, поскольку поток 2 не пытается использовать ресурс dдо позднего времени.
rorlork
1
@ rcrmn ты уверен, что :)не должно быть ложным и :(истинным?
Tyilo

Ответы:

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))
KSab
источник
Это ложный ответ pastebin.com/V5MVgNgS
Tyilo
@Tyilo выводит True для меня; как именно ты это делаешь?
KSab
о, это было только чтение одной строки для меня. Как вы должны управлять этим?
Tyilo
@Tyilo Я изменил формат, чтобы быть функцией, которая принимает многострочную строку в качестве ввода
KSab
5

Python - 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':)'
Tyilo
источник
1
Используется ;для объединения строк с отступом для сохранения символов. Аналогично, делайте ваши заявления одним лайнером.
Исаак
@isaacg и туз, спасибо! Я думаю, что я улучшил его настолько, насколько мог, используя ваши советы.
Tyilo
Кстати, если вы не против скопировать ввод из файла (или дважды нажать Ctrl + D), вы можете сделать for r in sys.stdinвместоfor r in sys.stdin.readlines()
user12205
@ace Я не вижу никакого другого поведения между использованием just sys.stdinили sys.stdin.readlines(), поэтому я изменил его, еще раз спасибо.
Tyilo
Вы можете удалить пробелы между printи':)'
user12205