|   |   | 
| 
 | "Семафоры" на управляемых блокировках | ☑ | ||
|---|---|---|---|---|
| 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 | 
        а разве Блокировка.Заблокировать() не работает уже?     | 
 
 | Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |