Инструкция блокировки — обеспечение монопольного доступа к общему ресурсу
Статья
Оператор lock получает взаимоисключающую блокировку заданного объекта перед выполнением определенных операторов, а затем снимает блокировку. Во время блокировки поток, удерживающий блокировку, может снова поставить и снять блокировку. Любой другой поток не может получить блокировку и ожидает ее снятия. Оператор lock гарантирует, что в любой момент выполняется только один поток.
Объект, возвращаемый Lock.EnterScope() методомDispose(), является ref struct объектом, который включает метод. Созданная using инструкция гарантирует, что область освобождается, даже если исключение создается с текстом инструкцииlock.
lock В противном случае оператор точно эквивалентен следующему:
Так как код использует try-finally инструкцию, блокировка освобождается даже в том случае, если исключение создается в тексте lock инструкции.
Выражение в тексте инструкции нельзя использоватьawait.lock
Рекомендации
Начиная с .NET 9 и C# 13, блокировка выделенного экземпляра объекта типа для оптимальной System.Threading.Lock производительности. Кроме того, компилятор выдает предупреждение, если известный Lock объект приведение к другому типу и заблокирован. Если используется более ранняя версия .NET и C#, блокировка на выделенном экземпляре объекта, который не используется для другой цели. Не используйте один и тот же экземпляр объекта блокировки для разных общих ресурсов: это может привести к взаимоблокировке или состязанию при блокировке. В частности, избегайте использования следующих экземпляров в качестве объектов блокировки:
this, как вызывающие также могут блокироваться this.
Typeэкземпляры, так как они могут быть получены оператором typeof или отражением.
экземпляры строк, включая строковые литералы, так как они могут быть интернированы.
Удерживайте блокировку в течение максимально короткого времени, чтобы сократить число конфликтов при блокировке.
Пример
В следующем примере определяется класс Account, который синхронизирует доступ к закрытому полю balance путем блокировки выделенного экземпляра balanceLock. Использование одного и того же экземпляра для блокировки гарантирует, что два разных потока не могут обновлять balance поле, вызывая Debit методы или Credit методы одновременно. В примере используется C# 13 и новый Lock объект. Если вы используете более раннюю версию C# или более старую библиотеку .NET, заблокируйте экземпляр object.
C#
using System;
using System.Threading.Tasks;
publicclassAccount
{
// Use `object` in versions earlier than C# 13privatereadonly System.Threading.Lock _balanceLock = new();
privatedecimal _balance;
publicAccount(decimal initialBalance) => _balance = initialBalance;
publicdecimalDebit(decimal amount)
{
if (amount < 0)
{
thrownew ArgumentOutOfRangeException(nameof(amount), "The debit amount cannot be negative.");
}
decimal appliedAmount = 0;
lock (_balanceLock)
{
if (_balance >= amount)
{
_balance -= amount;
appliedAmount = amount;
}
}
return appliedAmount;
}
publicvoidCredit(decimal amount)
{
if (amount < 0)
{
thrownew ArgumentOutOfRangeException(nameof(amount), "The credit amount cannot be negative.");
}
lock (_balanceLock)
{
_balance += amount;
}
}
publicdecimalGetBalance()
{
lock (_balanceLock)
{
return _balance;
}
}
}
classAccountTest
{
staticasync Task Main()
{
var account = new Account(1000);
var tasks = new Task[100];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() => Update(account));
}
await Task.WhenAll(tasks);
Console.WriteLine($"Account's balance is {account.GetBalance()}");
// Output:// Account's balance is 2000
}
staticvoidUpdate(Account account)
{
decimal[] amounts = [0, 2, -3, 6, -2, -1, 8, -5, 11, -6];
foreach (var amount in amounts)
{
if (amount >= 0)
{
account.Credit(amount);
}
else
{
account.Debit(Math.Abs(amount));
}
}
}
}
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Отзыв о .NET
.NET — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
Присоединитесь к серии встреч для создания масштабируемых решений искусственного интеллекта на основе реальных вариантов использования с другими разработчиками и экспертами.