В моем коде у меня есть метод, который обрабатывает перевод денег с одной учетной записи на другую. Очевидно, что этот метод должен обеспечивать выполнение только одной транзакции для каждой учетной записи в любой момент выполнения программы. Я выполнил эту проверку с помощью 2 вложенных блокировок (Account
является DB объект aith уникальный целочисленный идентификатор):Одновременное блокирование нескольких объектов
public void Transfer(Account from, Account to, decimal amount)
{
lock(GetLockObject(from))
{
lock(GetLockObject(to))
{
DoTransfer(from, to, amount);
}
}
}
private static Dictionary<int, object> lockObjects = new Dictionary<int, object>();
private static GetLockObject(Accont acc)
{
lock (lockObjects)
{
var lockObject = lockObjects[acc.Id];
if (lockObject == null)
{
lockObject = new object();
lockObjects[accId] = lockObject;
}
return lockObject;
}
}
Это, кажется, работает хорошо, но у меня есть 2 проблемы:
- Код может вызвать тупик, если метод вызывается одновременно с теми же 2 учетными записями, что и его аргументы:
Transfer(acc1, acc2, 10);
Transfer(acc2, acc1, 10);
Как мне избежать взаимоблокировки здесь? - Можно ли добиться того же результата лучше (с точки зрения производительности, надежности и т. Д.), Чем использовать вложенные блокировки?