Имя: Пароль:
1C
1С v8
"Семафоры" на управляемых блокировках
0 mwide
 
25.01.13
15:52
Можно ли с помощью блокировок сделать что-то типа семафора?
Задача такая - есть фрагмент кода, требуется, чтобы он мог выполняться только одним клиентом. Подробнее - есть регистр и константа. В регистр пишутся какие-то данные, константа содержит счетчик записей в регистр. Клиент, который хочет произвести запись, считывает значение константы, пишет в регистр данные, затем меняет значение константы. Нужно, чтобы вся эта операция, от чтения константы и до финальной записи в неё, могла выполняться только одним сеансом. Т.е. если какой-то сеанс собирается начать чтение, он ждал бы, пока другой сеанс не завершит запись.

Попробовал делать так:

блокировка = новый БлокировкаДанных;
элементБлокировки = блокировка.Добавить("Константа.Счетчик");    элементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
блокировка.Заблокировать();
значение = константы.счетчик.получить();

...какие-то действия...

константы.счетчик.установить(значение+1);
блокировка = неопределено;

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

Подскажите, подходит ли вообще механизм управляемых блокировок для решения задачи, и что не так делаю?
1 Fragster
 
гуру
25.01.13
15:54
в транзакции?
2 mwide
 
25.01.13
15:59
(1) то же самое. Оба сеанса входят в транзакцию. Есть разница, где начинать транзакцию - до блокировки или после?
3 hhhh
 
25.01.13
16:11
(2) ну вообще блокировку выбросить если, оставить только транзакцию?
4 SUA
 
25.01.13
16:14
процессорного времени жалко?
блокировка + транзакция
5 Maxus43
 
25.01.13
16:14
>>константа содержит счетчик записей в регистр
до этого дочитал и всё.
Неправильная реализация имхо
6 mwide
 
25.01.13
16:16
(3) на сколько я понимаю, транзакция не означает блокировку данных, а гарантирует только, что данные будут либо записаны все, либо не записано ничего
7 mwide
 
25.01.13
16:16
(4) как, например? где нужно начинать транзакцию, до или после блокировки?
8 hhhh
 
25.01.13
16:19
(6) нет, неправильно понимаешь. Транзакция не даст второму запустить такую же транзакцию. Он будет ждать.
9 mwide
 
25.01.13
16:20
предупреждение("перед начать транзакцию");
начатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);    предупреждение("транзакция начата");
   
блокировка = новый БлокировкаДанных;
элементБлокировки = блокировка.Добавить("Константа.Счетчик");    
элементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
предупреждение("перед блокировкой");
блокировка.Заблокировать();
предупреждение("Блокировка выполнена");

В таком варианте, оба сеанса благополучно проходят начало транзакции и потом оба зависают на выполнении блокировки...
10 SUA
 
25.01.13
16:22
до
сразу - заблокировать, прочитать/записать, отпустить

РежимБлокировкиДанных (DataLockMode)
Исключительный (Exclusive)
Описание:

Исключительная блокировка не позволит конкурирующему процессу установить разделяемую или исключительную блокировку по этому же условию.

хотя, судя по описанию, должно и по (0) работать
11 zmaximka
 
25.01.13
16:24
А режим управления блокировками какой для конфигурации установлен?
12 mwide
 
25.01.13
16:25
(10) для конфы в целом - автоматический
13 Fragster
 
гуру
25.01.13
16:26
(9) убери предупреждение перед блокировкой
14 mwide
 
25.01.13
16:26
Попробовал с транзакцией - если один процесс успевает выполнить и открытие транзакции, и блокировку - второй становится в ожидание на открытии транзакции.

Если же первый делает только открытие, второй так же может сделать открытие, и потом оба становятся на блокироке, пока один не решит сообщить о конфликте блокировок
15 Fragster
 
гуру
25.01.13
16:27
(12) мляяяяяяя.... выбери в запросе "Для изменения" константу твою...
16 mwide
 
25.01.13
16:27
(13) что это изменит? предупреждение там для проверки, чтобы контроллировать, кто в каком месте выполняется
17 Maxus43
 
25.01.13
16:33
(12) о каких Управляемых блокировках тогда идёт речь то вобще?
18 Maxus43
 
25.01.13
16:40
кстати, сменилось же парадигма уже что константы в 1-й строке хранятся в скуле?
19 mwide
 
25.01.13
16:44
(17) ошибся, в конфе режим блокировок управляемый
20 etc
 
25.01.13
16:44
(18) лень смотреть :)
21 mwide
 
25.01.13
16:46
если сделать запрос ДЛЯ ЗАПИСИ, то при одновременном входе в транзакцию двух сеансов, после запроса обращение к константе блокируется в обоих сенасах... (выстрел в голову)
22 mwide
 
25.01.13
16:46
в смысле - запрос ДЛЯ ИЗМЕНЕНИЯ
23 etc
 
25.01.13
16:47
(0) сделай по другому. При входе в кусок кода пусть пишется строка в регистр "Я Вася Пупкин выпоняю эту процедуру". А при выходе из процедуры очищать. И проверку "Если ТекущийПользователь <> ПользовательИзРегистра ТО ВызватьИсключение("не моё")"
24 etc
 
25.01.13
16:48
главное чтобы сеансы не падали :)
25 Bober
 
25.01.13
16:52
(0) если нужен счетчик и "хитрая" блокировка, то сделай служебный план обмена и блокируй узел. Фишка в том, что блокировать узел можно без транзакции и там есть встроенный счетчик
26 zmaximka
 
25.01.13
16:57
А у самой константы режим управления какой?
27 zmaximka
 
25.01.13
16:57
В смысле режим управления блокировками
28 mwide
 
25.01.13
17:03
(27) у константы режим управляемый
29 Reset
 
25.01.13
17:06
(26) А какое это имеет значение в свете (12)? :)
30 zmaximka
 
25.01.13
17:06
По идее код из (0) должен работать
31 Maxus43
 
25.01.13
17:07
(29) > (19) автор не определился ещё)
32 Bober
 
25.01.13
17:08
(0) даже еще веселее, сделай план обман  семаформы и моргай сколько хочется
33 Reset
 
25.01.13
17:16
(31)(27) аа, сорри. По диагонали тему просмотрел.
34 mwide
 
25.01.13
17:17
(32) всё классно, только сеанс на ожидание не становится... если только обработать исключение и крутиться в цикле, пока не получится заблокировать... Наверное, если с блокировками не получится, сделаю так, спасибо за идею :) хотя с жесть, конечно :)
35 Bober
 
25.01.13
17:20
(34) так тоже самое у тебя с блокировками будет, только ожидание на блокировку будет идти дольше (от 40 сек). А тут сразу да или нет.
36 Reset
 
25.01.13
17:21
Попробовал (9), правда без кучи этих предупреждений (достаточно одного перед завершением транзакции) - все работает.
37 Reset
 
25.01.13
17:22
(34) разберись с блокировками, пригодится ;)
38 mwide
 
25.01.13
17:24
(37) как ты без предупреждений контролируешь, в каком месте какой сеанс выполняется?
39 Reset
 
25.01.13
17:47
(38) цитата:
"(достаточно одного перед завершением транзакции)"
40 Живой Ископаемый
 
25.01.13
20:07
(18) сменилась в 14релизе
41 Torquader
 
26.01.13
01:43
Открытие транзакции на самом деле никакой блокировки не вызывает - оно сообщает серверу, что нужно изменить режим отслеживания изменений. То есть после НачатьТранзакцию() система продолжит исполнение кода до первого обращения к данным - если сначала будет произведено чтение, а потом запись, то две транзакции "столкнуться", то есть заблокируют друг друга. После этого сервер каким-то случайным образом "принесёт одну в жертву".
Можно, конечно, сделать запись в какую-то таблицу текущего времени, чтобы гарантировано всех заблокировать, а уже после этого продолжить.
Если есть общая директория, то можно использовать открытие файла на запись - только один процесс его сможет открыть, но в серверной версии 1С общая директория может быть только на сервере.
42 mwide
 
29.01.13
10:45
(41) спасибо, идея с записью работает. Остановился на таком варианте:
Завести отдельную константу под семафор, перед началом доступа к критическому ресурсу открывать транзакцию и пытаться в неё писать. Тогда сеанс, который первый произел запись, получает управление, остальные ждут, пока он не закроет транзакцию.

Собственно задача была такая - сеанс читает значение счетчика из константы, наращивает его и записывает обратно. Нужно не дать двум сеансом прочитать одно и то же значение. То есть, если первый уже начал читать, то второй не читает, пока первый не запишет.
43 Torquader
 
01.02.13
02:45
(42) Вообще-то, в нормальных системах это называется AddCounter, то есть увеличение счётчика, которое должно делаться прозрачно в транзакциях - и есть специальные объекты "генераторы" в SQK-системах, только вот 1С до этого ещё не доросла.
44 France
 
01.02.13
02:53
Почему не доросла? А нумерация\кодирование объектов? Чего и автору желаю
45 Torquader
 
04.02.13
01:03
(44) Нумерация сделана встроенными средствами - и, надо сказать, даже работает, но использовать её без объекта невозможно.
Вы ещё генерацию GUID вспомните - она там тоже есть только потому, что объекты по GUID идентифицируются.
46 mistеr
 
04.02.13
01:22
(42) А можно исходную бизнес-задачу? Чисто поржать над архитектурной композицией в целом.
47 France
 
04.02.13
08:36
(45) не касаясь исходной задачи: что мешает создать справочник "Автонумерация" и создавать так нужные автору уникальные и контролируемые номера?
48 Torquader
 
05.02.13
02:50
(47) На самом деле, проблема автонумерации нерешаема в общем случае. Конечно, если мы последовательно что-то нумеруем, то нужно только запретить параллельное исполнение кода, чтобы не было двух одинаковых номеров. Но, как только с системой начинают работать пользователи, начинаются сюрпризы - например - кто-то получил номер, а потом удалил пронумерованный объект - в нумерации получается дырка. Конечно, при желании её можно отловить и заполнить, но тогда нарушится последовательность объектов, так как позднее созданный будет иметь меньший номер.
1С прекрасно нумерует в момент сохранения, но никто не застрахован от того, что пронумерованный объект не будет удалён.
49 МуМу
 
05.02.13
05:54
(48) Нормально все решается, вопрос только как задачу ставить. Например можно в "дырки " ставить новые элементы, по диапазону номерации.
50 0xFFFFFF
 
05.02.13
07:05
(41) че так сложно то? Стандартный механизм блокировок уже неработает чтоли?
51 tuxik07
 
05.02.13
08:22
а разве Блокировка.Заблокировать() не работает уже?
2 + 2 = 3.9999999999999999999999999999999...