Взаимные блокировки в 1С

Определение

Взаимная блокировка (англ. deadlock) — ситуация в многозадачной среде или СУБД, при которой несколько процессов находятся в состоянии бесконечного ожидания ресурсов, занятых самими этими процессами. В литературе также встречаются синонимы как «тупиковая блокировка», «дедлок»…
Есть также частный случай «постоянной блокировки» (англ. Livelock) — ситуация: система не «застревает» (как в обычной взаимной блокировке), а занимается бесполезной работой, её состояние постоянно меняется — но, тем не менее, она «зациклилась», не производит никакой полезной работы.
Жизненный пример такой ситуации: двое встречаются лицом к лицу. Каждый из них пытается посторониться, но они не расходятся, а несколько секунд сдвигаются в одну и ту же сторону.

Область блокирования

Применительно к информационным системам 1С:Предприятие надо отметить прежде всего области блокировок.
Помимо классических блокировок на стороне СУБД, например MS SQL Server, сервер приложений 1С имеет собственный механизм установки «управляемых» блокировок. Т.е. взаимное блокирование может быть не только между блокировками субд, но и блокировками сервера 1С, или комбинированный вариант.
Но и это еще не все, блокироваться также могут ресурсы в тех случаях, когда на сервере  приложений 1С существует больше одного рабочего процесса (где исполняется код). Не часто, но в ресурсах рабочих процессов может возникать взаимное блокирование исполняемых процессов.

Участники блокирования

Участниками процессов взаимоблокировок являются некие действия, выполняемые в рамках сессий пользователей 1С (в том числе фоновых заданий). Вероятность возникновения взаимоблокировок есть всегда, взаимоблокировок не может быть только  когда существует один процесс, либо процессы не делят между собой общих ресурсов. В остальных случаях главный вопрос — это насколько высока вероятность взаимной блокировки.
Цель программиста — свести к минимуму вероятность возникновения взаимной блокировки. Снижение вероятности взаимной блокировки за счет увеличения вероятности увлечения ожиданий на блокировках чаще всего «меньшее зло».
В реально работающей системе достаточно часто участников ситуации взаимного блокирования может куда больше чем 2 или 3 участника. В очень сложных случаях взаимного блокирования  участвуют десятки сессий и предусмотреть в коде заранее такие ситуации очень сложно.

Условия возникновения взаимной блокировки

Для возникновения ситуации взаимной блокировки, необходимо выполнение следующих четырех условий одновременно:
1. Условие взаимного исключения. Каждый ресурс в текущий момент или занят ровно одним процессом или свободный. То есть, ресурсы находятся в режиме эксклюзивного пользования.
2. Условие удержания и ожидания. Процессы, в текущий момент удерживают полученные ранее ресурсы, могут делать запросы на получение новых ресурсов.
3. Условие отсутствия принудительного освобождения ресурсов. Невозможно заставить процесс освободить ранее полученные ресурсы.Процесс, обладающий ресурсами, должен сам их увольнять.
4.Условие циклического ожидания. Должно существовать кольцевая последовательность из двух или более процессов, каждый из которых ожидает увольнение ресурса, удерживаемого следующим членом последовательности. Иными словами, должно существовать множество процессов {P0, P1,… Pn}, так, что процесс P 0 ожидает освобождения ресур процесса P 1, P 1 ожидает P 2,…, P N — 1 ожидает P N, а P N ожидает освобождения ресурсов процессом P 0. Для возникновения ситуации взаимной блокировки, необходимо выполнение всех четырех условий одновременно. Если хотя бы одно из условий не выполняется, взаимная блокировка невозможна.

Факторы, снижающие вероятность взаимного блокирования

1. минимизировать время транзакций и длительность операций (даже ускорение запроса — это очень хорошо)
2. минимизировать количество объектов, которые используются в одной операции или транзакции (в том числе заменять объектное чтение объектов на запросы с указанием нужных свойств объекта и отборами)
3. захватывать все нужные объекты для операции или транзакции «сразу», а не постепенно (т.е. если вы собираетесь читать остатки с блокированием на чтение, лучше сразу заблокировать на запись, если вы точно знаете что будете писать, или как делается в некоторых случаях, сначало записываются движения а потом просто проверяются отрицательные остатки и откатывается в случаи нахождения минусов).
4. не захватывать новые ресурсы не отпустив предыдущие, в том числе разбивать большие операции или транзакции на пакет более мелких
5. не пересекаться по ресурсам, работать с версиями объектов (не всегда это можно в 1С), не создавать любого из 4х условий , описанных в предыдущем разделе.
в 1С нет возможности узнавать наложенные блокировки в явном виде и управлять ими, но теоретически существуют такие приемы как
6. В случаях, когда процесс запрашивает доступ к ресурсу, который не может быть сразу предоставлено, он освобождает остальных занятых ресурсов, и передает их в очередь на запрос. Работу процесса будет возобновлено после получения доступа ко всем ресурсам в очереди (старые и новые ресурсы).
7. Сначала проверить возможность предоставления ресурса, если возможность предоставить ресурс отсутствует из-за использования его другим процессом, который ожидает освобождения некоторых других ресурсов, то освободить этот ресурс, и передать его процесса-заказчику. Если необходимый ресурс как недоступен, так и процесс, что его использует, не ожидает освобождения других ресурсов, то перевести процесс, подал запрос, в состоянии ожидания. Во время ожидания, некоторые содержащиеся ним ресурсы могут быть освобождены из-запросы третьих процессов. Процесс возобновляет работу после того, как получит необходимые ресурсы и ресурсы, которые были уволены во время ожидания.
8. Для упорядочивания  захвата ресурсов всем типам ресурсов задаются «порядковые номера», и затем обеспечить выполнение процессами правила «захватывать ресурсы только в возрастающем порядке номеров».
9. Указать «расписание» когда определенные ресурсы уже «забронированы» и их захватывать даже не надо пытаться.

Анализ взаимных блокировок

При анализе большого количества взаимоблокировок в системе всегда имеет смысл начинать с самых простых взаимоблокировок – с минимальным количеством участников и с самыми простыми схемами. Высока вероятность того, что устранив одну простую взаимоблокировку вы одновременно устраните несколько других – в том числе более сложных.
Чаще всего в 1С-системах блокировки возникают из-за неоднородного порядка захвата ресурсов. Захват ресурсов в разном порядке возникает с увеличением числа разнородных по виду деятельности сеансов пользователей.
Понятно, что в идиале нужно изменить порядок захвата ресурсов.
Для решения этой проблемы нужно видеть хронологию того, как какой процесс что захватывал.
Другой популярный вариант взаимоблокировок заключается в попытках нескольких сессий наложить монопольную неразделяемую блокировку на общий ресурс. Отличительная особенность этих ситуаций — предварительный захват ресурсов разделяемом режиме. Т.е. если бы ресурсы были бы сразу захвачены монпольно, то проблемы то не было. Но решение проблемы установкой неразделяемой блокировки на объект — не единственное в данном случаи. Можно рассмотреть вариант либо вообще не блокировать сначала объект, либо снять разделяемую блокировку, если это возможно сделать с помощью управляемой блокировки. В последнем случаи речь идет не о блокировках субд, а блокировках на стороне сервера приложений 1С.
Разумеется для второго случая знание хронологии событий позволит принять правильное решение для наиболее эффективного устранения проблемы.

Инструмент анализа

Наш сервис анализа взаимных блокировок позволяет узнать:
1. о фактах взаимных блокировок на стороне MS SQL Server
2. о количестве и группировке по месту возникновения в коде 1С
3. о хронологии событий, приведших к каждому факту взаимной блокировки

Воспользоваться бесплатным инструментом: http://www.gilev.ru/deadlock/