Вам не нужно беспокоиться об этом. Из документации Мнесия:
Блокировки чтения могут быть общими, что означает, что если одной транзакции удается получить блокировку чтения для элемента, другие транзакции также могут получить блокировку чтения для того же элемента. Однако, если у кого-то есть блокировка чтения, никто не может получить блокировку записи для того же элемента. Если у кого-то есть блокировка записи, никто не может получить блокировку чтения или блокировку записи для одного и того же элемента.
Если транзакция имеет блокировку чтения объекта, этот объект не может быть отредактирован другой транзакцией.
Допустим, у вас есть две транзакции, T1 и T2, которые выполняются параллельно:
- T1 выполняет
mnesia:match_object
и получает блокировку чтения для всех возвращаемых объектов.
- T2 делает эквивалент
mnesia:match_object
и получает блокировку чтения для тех же объектов.
- T2 пытается получить блокировку записи объектов (для ее редактирования).
- Mnesia автоматически прерывает T2, чтобы повторить попытку позже.
- T1 получает блокировку записи на объекты и редактирует их.
- T1 заканчивается.
- Мнезия повторяет Т2.
Обратите внимание, что T2 может быть повторен несколько раз, в зависимости от того, сколько времени требуется T1 для завершения (т. Е. Снятия блокировок).
Согласно моим тестам, поведение блокировки mnesia:match_object
не согласовано. Например, mnesia:match_object(mytable, {mytable, 2, '_'}, LockType)
заблокирует только запись с ключом 2, но mnesia:match_object(mytable, {mytable, '_', test}, LockType)
заблокирует всю таблицу.
Также обратите внимание, что документация неверна, mnesia:match_object(Table, Pattern, write)
работает и, похоже, следует тому же шаблону, что и «read», т.е. если вы укажете ключ, только соответствующая запись будет заблокирована от записи; если вы не укажете ключ, вся таблица будет заблокирована от записи.
Вы можете проверить это самостоятельно, выполнив что-то вроде этого:
test() ->
mnesia:transaction(fun()->
Table = mytable,
Matches = mnesia:match_object(Table, {Table, 2, '_'}, write),
io:format("matched: ~p~n", [Matches]),
spawn(fun()->mnesia:transaction(fun()->
io:format("trying to read~n",[]),
io:format("read: ~p~n", [mnesia:read(Table, 2, read)])
end) end),
timer:sleep(1000),
RereadMatches = lists:map(fun(#mytable{id=Id}) -> mnesia:read(Table, Id, write) end, Matches),
io:format("reread matches: ~p~n", [RereadMatches])
end).
Изменяя шаблон и тип блокировки, передаваемые на match_object
, а номер ключа и тип блокировки, передаваемые на mnesia:read
в порожденном процессе (или используя mnesia:write
), вы можете проверить различные варианты блокировки.
Приложение: См. сообщение Ульфа Вигера на ту же тему.
Приложение 2: См. Раздел «Изоляция» в руководстве пользователя Mnesia.
Редактировать: Выше все было сделано для таблицы типа набора, match_object
поведение блокировки может быть другим для таблицы типа сумки.