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