У меня возникли проблемы с потоком в приложении OLTP. При просмотре кода, я нашел следующее:
lock (_pendingTransactions)
{
transaction.EndPointRequest.Request.Key = (string)MessageComparer.GenerateKey(transaction.EndPointRequest.Request);
if (!_pendingTransactions.ContainsKey(transaction.EndPointRequest.Request.Key))
{
_pendingTransactions.Add(transaction.EndPointRequest.Request.Key, transaction);
return true;
}
else
{
return false;
}
}
Как вы можете видеть в фрагменте, существует блокировка объекта, который изменяется в блоке блокировки. Что-то плохое с этим? У кого-нибудь были проблемы с этим?
Использование блокировки таким образом часто обескураживается, при этом рекомендуется использовать выделенное поле блокировки (переменная члена класса). Специальное поле блокировки имеет тип Object
и обычно выглядит так:
private object _pendingTransactionLock = new object();
Если сам объект имеет некоторое представление о потоках, эта переменная блокировки может принадлежать классу _pendingTransaction
. В противном случае он может принадлежать _pendingTransaction
в поле, объявляющем класс.
Вы не говорите, какой тип _pendingTransaction
. Если это встроенный класс коллекции, который предоставляет свойство SyncRoot
, это может быть хорошим выбором для блокировки.
См. Jon Skeet Выбор того, что блокировать.
Вообще говоря, один будет блокировать объект, потому что он собирается его модифицировать (или читать), поэтому в этом нет ничего неправильного.
Вероятно, генерация ключа может быть выведена за пределы блокирующего блока, чтобы уменьшить продолжительность блокировки. Кроме этого, это почти канонический пример блокировки, который защищает список/коллекцию/массив: получить блокировку, проверить, существует ли ключ, добавить ключ, если он еще не существует, отпустить блокировку.