Напишите кратчайший код для создания тупика . Выполнение кода должно быть остановлено, так что это не работает:
public class DeadlockFail extends Thread{ //Java code
public static void main(String[]a){
Thread t = new DeadlockFail();
t.start();
t.join();
}
//this part is an infinite loop; continues running the loop.
public void run(){while(true){}}
}
Не нужно быть уверенным, что код заходит в тупик , просто почти наверняка (если вы будете работать в течение бесконечного времени, он заблокируется).
code-golf
concurrency
Джастин
источник
источник
Code execution must halt
Я не понимаю Как это тупик, если он останавливается? Ты имеешь в виду, что он будет ждать чего-то, а не просто крутится, как мудак?Ответы:
Дьялог АПЛ (10)
⎕TSYNC
заставляет поток ждать, пока не закончится данный поток,⎕TID
выдаст текущий поток.Dyalog APL может распознавать тупики, поэтому он немедленно отвечает
Самое интересное в том, что вам даже не нужно создавать никаких дополнительных потоков, заставляя поток пользовательского интерфейса ждать себя достаточно.
Если это обман и новые темы действительно требуются, вы можете сделать это в 27 символах:
F & x
запускаетсяF
в новом потоке по значениюx
и возвращает идентификатор потока. Так:{⎕TSYNC⎕TID+1}&0
создает поток, который будет синхронизироваться с потоком, чей ID на единицу выше, чем его собственный,⎕TSYNC&
создает новый поток, который будет синхронизироваться с предыдущим потоком, и который получает идентификатор на единицу выше, чем поток, который был только что создан (при условии, что больше ничего не создает потоки).∇
вызывает бесконечный цикл (поэтому мы продолжаем создавать потоки до тупика).Это приведет к взаимоблокировке, как только второй поток будет создан до того, как начнется запуск первого, что довольно скоро:
источник
⎕TSYNC 0'.
⎕TID` is0
.Go, 42
Извините, downvoter, за то, что не предоставил, как это работает. Это создает анонимный канал целых и читает из него. Это приостанавливает основной поток до тех пор, пока значение не будет отправлено по каналу, что, очевидно, никогда не происходит, поскольку другие потоки не активны, и, таким образом, взаимоблокировка.
источник
Рубин, 39 знаков
Идея использовать кросс-соединение, бесстыдно украденное из Java-ответа Йоханнеса Куна .
Мы можем сбрить четыре символа (до 35 ), если настроим код для конкретной среды. IRB консоли JRuby является однопоточным:
Это мое предыдущее решение:
завести поток на мьютекс легко:
но это не правильный тупик, потому что второй поток технически не ждет первого потока. «Держи и жди» - это необходимое условие тупика, согласно Википедии. Первый поток не ждет, а второй поток не содержит ничего.
Рубин,
9795 персонажейэто классический тупик. Два потока конкурируют за два ресурса, повторяя попытку в случае успеха. Обычно они застряли в течение секунды на моей машине.
Но если с бесконечным количеством потоков (ни один из которых не потребляет ЦП бесконечно, а некоторые из которых тупик), то все в порядке,
Рубин,
8785 символовСогласно моему тесту, он терпит неудачу после того, как число потоков достигает примерно 4700. Надеемся, что оно не будет работать до тех пор, пока у каждого потока не будет возможности запустить (таким образом, либо взаимная блокировка, либо завершение и освобождение места для нового). Согласно моему тесту, количество потоков не падает после возникновения ошибки, то есть во время теста возникла взаимоблокировка. Также ИРБ умерла после теста.
источник
o
иp
переменные? Не могли бы вы просто пройтиm
иn
для новой темы?m
иn
являются глобальными. Оба потока видят их в одинаковом порядке.o
иp
являются локальными для потока (ограничены итерацией цикла). Использованиеt[...]
, вероятно, обойдется дорого, и я не вижу лучшего способа передачи параметров потоку, чем с помощью замыкания. Добавление дополнительных параметровnew
удлиняет код на два символа.T=Thread;T.new{T.main.join}.join
Python, 46
(Само-взаимоблокировки)
источник
from threading import* Semaphore(0).acquire()
короче на один байт, я думаюBash + GNU coreutils, 11 байт
Создает случайный FIFO
x
в текущем каталоге (поэтому вам не нужно иметь файл с таким именем). FIFO могут быть удалены так же, как и обычные файлы, поэтому их не сложно очистить.FIFO имеет сторону записи и сторону чтения; попытка открыть один блок до тех пор, пока другой процесс не откроет другой, и это, кажется, намеренно было разработано как примитив синхронизации. Учитывая, что здесь есть только один поток, как только мы пытаемся открыть его
<x
, мы застреваем. (Вы можете снять тупик, записав данные в FIFO из другого процесса.)Этот тип тупика отличается от того, когда есть два ресурса, и каждый из двух потоков имеет один и нуждается в другом; скорее, в этом случае ресурсов нет, и процесс нуждается в них. Основываясь на других ответах, я думаю, что это имеет значение, но я могу понять, как тупиковый пурист может запретить ответ.
Если подумать, я могу подумать о трех тупиковых ситуациях:
«Традиционный» тупик: два потока каждый ожидают снятия блокировки, которая удерживается другим потоком.
Отдельный поток ожидает снятия блокировки, но он удерживает сам замок (и, таким образом, блокирует себя от возможности снять его).
Один поток ожидает освобождения примитива синхронизации, но примитив синхронизации запускается в естественно заблокированном состоянии и должен быть разблокирован извне, и ничего для этого не запрограммировано.
Это тупик типа 3, который принципиально отличается от двух других: теоретически вы можете написать программу для разблокировки рассматриваемого примитива синхронизации, а затем запустить его. Тем не менее, то же самое относится к взаимоблокировкам типа 1 и 2, учитывая, что многие языки позволяют вам освобождать блокировку, которой вы не владеете (вы не должны и не будете иметь причины делать это, если у вас была причина в первую очередь используйте замки, но это работает…). Также стоит рассмотреть такую программу, как
mkfifo x;<x;echo test>x
; эта программа является своего рода противоположностью взаимоблокировке типа 2 (она пытается чтобы открыть оба конца FIFO, но он не может открыть один конец до тех пор, пока он не откроет другой конец), но он был сделан из этого путем добавления дополнительного кода, который никогда не запускается после этого! Я думаю, проблема в том, что ли блокировка заблокирована или нет, зависит от намерения за использованием блокировки, поэтому сложно определить объективно (особенно в случае, подобном этому, где единственная цель блокировки - преднамеренно создать тупик).источник
C #, 100
Смотрите: тупик без блокировки
источник
static C
вMain
?Баш с glibc, 6 байтов
Извините, что оживил старую ветку, но не удержался.
Как корень:
От человека pldd :
источник
Ява, 191
Ungolfed:
Запускает новый
join
поток и на нем (дождитесь окончания этого потока), пока новый поток делает то же самое с исходным потоком.источник
Error
вместоException
?Thread.join()
бросаетInteruptedException
, который не является подклассомError
.Tcl, 76
Тупик.
Это создаст новый поток и скажет другому потоку отправить моему потоку сообщение (скрипт для выполнения).
Но отправка сообщения в другой поток обычно блокируется до тех пор, пока скрипт не будет выполнен. И пока он блокируется, сообщения не обрабатываются, поэтому оба потока ждут, пока другой обработает их сообщение.
источник
thread::send
ставит в очередь сценарий, который должен быть выполнен в другом потоке, и ожидает его завершения. Итак, в конце у нас есть Нить 1, ожидающая Нить 2, и Нить 2, ожидающая Нить 1.альтернативный java с нарушением монитора (248 чар)
источник
Scala, 104 байта
Блок инициализации lazy val приостанавливается, пока не будет выполнено условие. Это условие может быть выполнено только путем чтения значения lazy val x - другой поток, который должен выполнить это условие, не может этого сделать. Таким образом, формируется круговая зависимость, и ленивый val не может быть инициализирован.
источник
Котлин, 35/37/55 байт
Общая тема:
Thread.currentThread().join()
.Исключая ошибки JVM / очень специализированный код для этой отправки, этот шоуд никогда не вернется, поскольку текущий поток выполнения теперь отключен, ожидая своей смерти.
Злое свойство: 35 байт (не конкурирует): 35 байт
val a=Thread.currentThread().join()
Размещение этого значения в любом месте, в котором объявление свойства является действительным, приведет к взаимоблокировке того, кто его инициализирует. В случае свойства верхнего уровня это будет загрузчик классов, инициализирующий сопоставленный класс JVM для этого файла (по умолчанию
[file name]Kt.class
).Не конкурирует, потому что «помещать это как свойство верхнего уровня в любом месте» является ограничительным.
Функция: 37 байт
fun a()=Thread.currentThread().join()
main (): 55 байт
fun main(a:Array<String>)=Thread.currentThread().join()
источник
PowerShell,
362823 байтаSelf-тупиковый. Мы получаем все процессы с
Get-Process
и затем терпеливо ожидаем завершения каждого из них ... что произойдет примерно никогда, поскольку процесс будет ждать сам по себе.Редактировать - 5 байтов сохранено благодаря Роману Грэфу
источник
(gps)|%{$_.waitforexit()}
на три байта короче и ожидает завершения всех процессов.gps
в этом случае паренсы не нужны , так что сэкономлено 5 байт.C (только для Linux), 31 байт - попробуйте онлайн!
Системный вызов 240 (0xf0) - это futex (2) или быстрый мьютекс пространства пользователя. В документации говорится, что первый аргумент - это указатель на futex, второй аргумент - это операция (0 означает FUTEX_WAIT, то есть дождитесь, пока другой поток разблокирует futex). Третий аргумент - это значение, которое, как вы ожидаете, будет иметь futex, пока он еще заблокирован, а четвертый - указатель на тайм-аут (NULL для без тайм-аута).
Очевидно, что, поскольку нет другого потока, чтобы разблокировать futex, он будет ждать вечно в самопричиненном тупике. Можно проверить (с помощью
top
или другого диспетчера задач), что процесс не использует процессорное время, как мы должны ожидать от заблокированного потока.источник
Юлия 0,6 , 13 байт
Язык новее, чем вопрос. Ожидание задачи (как подпрограмма go, в настоящее время будет в том же потоке, в будущих версиях Julia это может быть в другом потоке), выполнение которого не запланировано.
Попробуйте онлайн!
источник
BotEngine, 3x3 = 9 (9 байт)
Шаг 5 заканчивается двумя ботами, которые бесконечно ждут друг друга для перемещения ... один бот не может двигаться, потому что он ждет, пока другой выйдет из нижнего правого квадрата, а другой бот не может двигаться, потому что он ждет Первый бот, чтобы выйти из нижней центральной площади.
источник
Модель водопада (Ratiofall), 13 байт
Попробуйте онлайн!
Вот забавный ответ со стены. Это самый простой бесконечный цикл в модели «Водопад» (переменные в модели «Водопад» многократно уменьшаются, когда ничего не происходит; эта программа определяет переменную, которая увеличивает себя всякий раз, когда она уменьшается, поэтому нет ничего, что могло бы случиться).
Вопрос требует тупика, а не бесконечного цикла. Однако мы можем использовать поведение конкретных реализаций. На уровне оптимизации 2 или выше (по умолчанию 3) интерпретатор Ratiofall обнаружит бесконечный цикл и оптимизирует его ... в тупик! Поэтому, по крайней мере, если мы считаем, что языки определяются их реализацией (что обычно имеет место на этом сайте), эта программа действительно определяет тупик, а не бесконечный цикл.
Вы можете увидеть свидетельство тупика из отчета о времени на сайте Try it Online! ссылка выше:
Программа работала в течение 60 секунд (до тех пор, пока TIO автоматически ее не завершил), но большую часть этого времени не было использования ЦП, времени, затраченного на запуск программы, и времени, затраченного ядром от имени программы.
Чтобы получить еще более веские доказательства, вы можете запустить Ratiofall в отладчике уровня системных вызовов, например
strace
; выполнение этого в Linux покажет блокировку интерпретатора приfutex
системном вызове, который пытается получить блокировку, которая никогда не будет снята.источник
Perl 6 , 24 байта
Попробуйте онлайн!
Создайте семафор с нулевыми разрешениями, а затем попытайтесь получить его.
источник