Почему выражение всегда верно для 'двойной проверки-блокировки'?
У меня есть одноэлементный объект "Сервис" и два метода для его инициализации и освобождения:
public class BaseService
{
protected static readonly object StaticLockObject = new object();
}
public abstract class WebServiceBase<TService> : BaseService
where TService : System.Web.Services.Protocols.SoapHttpClientProtocol, new()
{
protected static void EnsureServiceIsOpened()
{
if (Service == null)
{
lock (StaticLockObject)
{
if (Service == null)
{
Service = new TService();
}
}
}
}
protected static void EnsureServiceIsClosed()
{
if (Service != null)
{
lock (StaticLockObject)
{
if (Service != null) // Why expression is always true
{
Service.Dispose();
Service = null;
}
}
}
}
Для строки с комментарием resharper (я использую версию 5.1) отображает упомянутое предупреждение...
Вопрос 1: почему?
Вопрос 2: почему не отображается "похожее" сообщение в методе EnsureServiceIsOpened?
Благодарю.
3 ответа
Это ошибка в движке анализа кода ReSharper 5.X. Исправлено в ReSharper 6.0.
Кстати, ReSharper 6 приносит больше материала для анализа паттернов с двойной блокировкой:)
Решарпер делает ограниченный анализ кода и видит два вложенных if
Заявления проверяются точно так же. В однопоточном окружении комментарий от resharper абсолютно верен - нет никакого способа Service
будет null
после первого if
, В многопоточной среде, конечно, это не относится, так как Service
может быть изменен снаружи. Это тот случай, когда вы должны аннотировать код для повторной резкости или лишнего сообщения для этого файла, так как это не выполняется в многопоточной среде.
Похоже, что Решарпер делает ошибку в этом анализе. поскольку Service
не является локальной переменной, она не может знать, что это выражение всегда будет истинным.
Причина, по которой ошибка не появляется в первой версии, скорее всего, потому что идиома двойной проверки-блокировки очень распространена, и это ее обычная форма. Они, вероятно, проверили для этого случая и удалили ошибочное предупреждение.
Техника отображается в EnsureServiceIsClosed
не является распространенным, потому что он содержит условия гонки. Другой поток может использовать объект, обозначенный Service
в то время как - или после того, как оно утилизируется Это было бы невозможно, если код, который использует Сервис, блокируется на StaticLockObject
, но если он захватывает блокировку, то нет смысла делать всю эту двойную проверку блокировки ригамаролы вокруг создания и утилизации объекта. Следовательно, совершенно очевидно, что этот код неисправен.