Я застрял в одном вопросе в интервью.
Учитывая два потока, и у каждого есть блокировка, как не гарантировать мертвую блокировку.
Мое знание - то, что не легко избежать мертвой блокировки, вот почему я застрял. Может кто-либо давать подсказку.
Спасибо!
Описание немного отсутствует, но если вы наложите порядок блокировки (например, если заблокированы A и B, никогда не блокируйте B, если вы уже не заблокировали A и никогда не отпускайте A, пока B заблокирован), то взаимоблокировки не произойдет.
Существуют известные алгоритмы предотвращения взаимоблокировки , которые могут определять, может ли возникновение взаимной блокировки, и предотвращать переход системы в это состояние. Например, Алгоритм Банкира .
При единственной блокировке невозможно зайти в тупик, если только кто-то не откажется снять блокировку - в этом случае ожидающий поток называется голодным. Для множественных блокировок они должны быть сняты в порядке, обратном их получению, и оба потока должны согласовать порядок.
Вы пытаетесь избежать такой ситуации:
A имеет блокировку 1, ожидающую блокировки 2
B имеет блокировку 2, ожидающую блокировки 1
Порядок блокировок предпочтительнее обнаружения тайм-аутов / взаимоблокировок, но иногда требуются тайм-ауты, особенно если вы не контролируете все компоненты в системе: следовательно таймаут / обнаружение тупика в базах данных. Если бы все вызывающие были достаточно умны, взаимоблокировки никогда бы не возникли, но обычно не все вызывающие достаточно умны.
Вероятно, ваши интервьюеры ожидали ответа WaitForMultipleObjects (). Это Windows API, который блокирует оба (или несколько) ресурсов одновременно.
Это означает, что если объект включает управляемый ресурс, нам также придется позаботиться об этом, потому что сборщик мусора не очистит его.
Это ложь. Сборщик мусора будет по-прежнему очищать управляемые ресурсы. Финализаторы также строго предназначены для уборки неуправляемых ресурсов, и, таким образом, вызов SupertFinalize () не повредит вам.
И так как вы новичок в IDisposable образец я буду предвидеть ваш следующий пункт путаницы: написание финализаторов. В C # следует писать финализатор только при работе с совершенно новым видом неуправляемого ресурса. Так, например, при наличии класса, который переносит тип System.Data.SqlClient.SqlConnection как часть уровня доступа к данным, не следует записывать финализатор для этого типа, поскольку вы по-прежнему имеете дело с тем же типом базового неуправляемого ресурса: подключения к базе данных SQL Server. О финализаторе для этого ресурса уже заботится базовый тип SqlConnection.
С другой стороны, если вы создаете поставщика ADO.Net для совершенно нового типа ядра СУБД, вам нужно будет внедрить финализатор в свой класс соединений, потому что это никогда не было сделано раньше.
-121--2786202-С одной блокировкой невозможно выйти из тупика, пока один не откажется освободить их блокировку - в этом случае ожидающий поток называется голодным. Для нескольких блокировок они должны быть разблокированы в обратном порядке, в котором они были получены, и оба потока должны согласовать заказ.
Чего вы пытаетесь избежать здесь такая ситуация:
A имеет блокировку 1 ожидание на блокировке 2
B имеет блокировку 2 ожидание на блокировке 1
-121--4617123-Большая работа по параллельному программированию сосредоточена на конструкциях без блокировки. Не точный ответ на ваш вопрос, но, как уже упоминал Эндрю на этой ниве, лучший способ избежать тупиковых ситуаций - вообще не запереться. Многие очень умные люди, работающие над вопросами параллелизма, придерживаются такого мнения.