BigHarry где-то в 2001
Иногда бывает нужно обеспечить выполнение некоторых обработок в «квазимонопольном» режиме, т.е. таким образом, чтобы обработка в один момент времени выполнялась только в одной сессии (база данных, разумеется, сетевая).
Например, это может быть загрузка документов или справочников из внешних источников, какие-то административные работы, «чистка» базы или что-то подобное. В любом случае, открывать базу в монопольном режиме ради выполнения одной обработки очень неудобно и не всегда возможно.
Следовательно, нужен какой-то механизм, позволяющий распознавать и блокировать ситуации одновременного доступа к обработке. Иными словами, нужен семафор.
Первое, что приходит на ум – использовать в качестве семафора константу. Но это плохое решение. Если клиент, установивший семафор, вдруг по какой-то причине отвалится (банальный сбой питания или «коврик выполнил недопустимую операцию и будет свёрнут»), то семафор так и останется поднятым.
Возвращать его в нулевое состояние придётся руками, а это сводит на нет всю идею семафора – и подниматься, и опускаться он должен на полном автомате. По этой же причине нельзя использовать в качестве семафора наличие/отсутствие каких-то файлов и т.п.
Возникает вопрос – а нельзя ли использовать для механизма блокировок и семафоров какие-либо штатные возможности V7? Можно. В частности, отлично подойдёт самый обыкновенный справочник.
Окончательное решение выглядит так:
- Заводим в конфигурации специальный справочник, например, SysLock
- Код каждого конкретного элемента будет соответствовать какому-либо конкретному событию, которое управляется семафором.
- Если элемент справочника удалось заблокировать, это значит, что семафор опущен и обработку можно запускать.
- Если блокировка не удалась – значит, семафор поднят и обработка уже кем-то используется.
- При закрытии формы обработки, использующей семафор, ссылка на блокируемый элемент справочника автоматически удаляется и семафор возвращается в нулевое состояние.
Вот как это выглядит на практике:
Перем _лок; // переменная модуля
Процедура ПриОткрытии()
_лок=СоздатьОбъект("Справочник.SysLock");
Если _лок.НайтиПоКоду("01",0)=0 Тогда Сообщить("не найден флаг 01"); СтатусВозврата(0); Возврат; КонецЕсли;
Если _лок.Блокировка(1)=0 Тогда Сообщить("кто не успел, тот опоздал"); СтатусВозврата(0); Возврат; КонецЕсли; КонецПроцедуры
Процедура ПриЗакрытии() // на всякий случай _лок.Блокировка(0); _лок=""; КонецПроцедуры
Такой механизм будет работать в любой ситуации – поскольку он построен на штатном механизме шаринга и блокировок. Даже при аварийном завершении сессии семафор будет корректно возвращён в исходное (нулевое) состояние.
В принципе, механизм блокировок можно использовать не только для контроля за доступом к отчётам и обработкам. С его помощью, например, можно программно получать список пользователей, гарантированно работающих в настоящий момент с базой данных, и делать другие интересные вещи… |