Каковы общие причины тупиков? - PullRequest
39 голосов
/ 09 февраля 2009

Замки трудно найти и их очень неудобно удалять.

Как я могу найти источники ошибок для взаимоблокировок в моем коде? Есть ли какие-то «тупиковые паттерны»?

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

Ответы [ 12 ]

29 голосов
/ 09 февраля 2009

Обновление: эта недавняя статья MSDN, Инструменты и методы для выявления проблем параллелизма , также может представлять интерес


Стивен Тауб в статье MSDN Монитор тупиковой ситуации устанавливает следующие четыре условия, необходимые для возникновения взаимоблокировок:

  • Ограниченное количество определенного ресурса. В случае монитора в C # (который вы используете, когда используете ключевое слово lock), это ограниченное число равно единице, поскольку монитор является блокировкой взаимоисключения (то есть только один поток может одновременно иметь монитор).

  • Возможность удерживать один ресурс и запрашивать другой. В C # это похоже на блокировку одного объекта, а затем блокировку на другом перед снятием первой блокировки, например:


lock(a)
{
...
    lock(b)
    {
            ...
    }
}
  • Нет возможности вытеснения. В C # это означает, что один поток не может заставить другой поток снять блокировку.

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

Он продолжает объяснять, что способ избежать взаимоблокировок - это избежать (или помешать) четвертому условию.

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

14 голосов
/ 09 февраля 2009

Классический сценарий взаимоблокировки: А удерживает блокировку X и хочет получить блокировку Y, в то время как B удерживает блокировку Y и хочет получить блокировку X. Поскольку ни один из них не может завершить то, что они пытаются сделать, оба будут ждать вечно ( если не используются таймауты).

В этом случае можно избежать тупиковой ситуации, если A и B получат блокировки в одном и том же порядке.

8 голосов
/ 09 февраля 2009

Насколько мне известно, никаких шаблонов взаимоблокировок (и 12 лет написания многопоточных торговых приложений). Но класс TimedLock очень помог в поиске взаимоблокировок, которые существуют в коде без масштабной переделки.

http://www.randomtree.org/eric/techblog/archives/2004/10/multithreading_is_hard.html

в основном, (в dotnet / c #) вы ищете / заменяете все ваши операторы «lock (xxx)» на «используя TimedLock.Lock (xxx)»

Если когда-либо обнаруживается взаимоблокировка (блокировка не может быть получена в течение указанного времени ожидания, по умолчанию - 10 секунд), возникает исключение. Моя локальная версия также сразу регистрирует трассировку стека. Пройдите вверх по трассировке стека (желательно отладочную сборку с номерами строк), и вы сразу увидите, какие блокировки удерживались в точке сбоя и какую пытались получить.

В dotnet 1.1, в описанной ситуации взаимоблокировки, если повезет, все заблокированные потоки выдают исключение одновременно. Таким образом, вы получите 2+ стековых трасс и всю информацию, необходимую для решения проблемы. (2.0+ может изменить внутреннюю модель потоков настолько, что это не повезло, я не уверен)

8 голосов
/ 09 февраля 2009

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

Например:

Транзакция A

UPDATE Table A SET Foo = 'Bar'
UPDATE Table B SET Bar = 'Foo'

Транзакция B

UPDATE Table B SET Bar = 'Foo'
UPDATE Table A SET Foo = 'Bar'

С большой вероятностью это может привести к тупику, поскольку Транзакция A получает блокировку для таблицы A, Транзакция B получает блокировку для таблицы B, поэтому ни один из них не получает блокировку для их второй команды, пока другая не закончила.

Все другие формы взаимоблокировок, как правило, возникают из-за интенсивного использования и внутренней блокировки SQL Server при выделении ресурсов.

4 голосов
/ 09 февраля 2009

Да - тупики возникают, когда процессы пытаются получить ресурсы в случайном порядке. Если все ваши процессы пытаются получить одинаковые ресурсы в одном и том же порядке, возможности взаимоблокировок значительно уменьшаются, если не устраняются.

Конечно, это не всегда легко организовать ...

2 голосов
/ 22 июня 2009

Я рекомендую прочитать эту статью Херб Саттер . В нем объясняются причины возникновения взаимоблокировок и предлагается структура этой статьи для решения этой проблемы.

1 голос
/ 12 ноября 2011

Условие, которое возникает, когда два процесса каждый ожидают завершения другого перед предыдущим. В результате обе процедуры зависают. это самая удобная многозадачность и клинт / сервер.

1 голос
/ 09 февраля 2009

Наиболее распространенный (по моим ненаучным наблюдениям) сценарий тупиковой ситуации с БД очень прост:

  • Два процесса что-то читают (например, запись в БД), оба получают общую блокировку на связанном ресурсе (обычно это страница БД),
  • Оба пытаются сделать обновление, пытаясь обновить свои блокировки до эксклюзивных - вуаля, тупик.

Этого можно избежать, указав предложение «FOR UPDATE» (или аналогичное, в зависимости от вашей конкретной СУБД), если за чтением должно следовать обновление. Таким образом, процесс получает эксклюзивную блокировку с самого начала, что делает описанный выше сценарий невозможным.

1 голос
/ 09 февраля 2009

Типичным сценарием являются несовпадающие планы обновления (таблицы не всегда обновляются в одном и том же порядке). Тем не менее, нередко возникают взаимоблокировки при большом объеме обработки.

Я склонен воспринимать взаимоблокировки как жизненный факт, это произойдет в тот или иной день, поэтому я подготовил свой DAL для обработки и повторной блокировки операции.

0 голосов
/ 09 ноября 2015

Чтобы избежать тупика, существует алгоритм под названием Алгоритм банкира .

Этот также предоставляет полезную информацию , чтобы избежать тупика.

...