Почему выражение всегда верно для 'двойной проверки-блокировки'? - PullRequest
6 голосов
/ 19 апреля 2011

У меня есть одноэлементный объект 'Service' и два метода для его инициализации и освобождения:

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 ]

4 голосов
/ 19 апреля 2011

Resharper проводит ограниченный анализ кода и видит, что два вложенных оператора if проверяют абсолютно одинаково. В однопоточном окружении комментарий от resharper совершенно верен - нет никакого способа, которым Service будет null после первого if. Конечно, в многопоточной среде это не применимо, так как Service может быть изменено извне. Это тот случай, когда вы должны аннотировать код для повторной резкости или перевыполнить сообщение для этого файла, поскольку оно не выполняется в многопоточной среде.

3 голосов
/ 19 апреля 2011

Похоже, что Решарпер делает ошибку в этом анализе. Поскольку Service не является локальной переменной, он не может знать, что это выражение всегда будет истинным.

Причина, по которой ошибка не появляется в первой версии, вероятнее всего потому, что идиома двойной проверки-блокировки очень распространена, и это ее обычная форма. Вероятно, они проверили этот случай и удалили ошибочное предупреждение.

Техника, отображаемая в EnsureServiceIsClosed, не распространена, поскольку содержит условие гонки. Другой поток может использовать объект, обозначенный Service во время или после его удаления. Это было бы невозможно, если код, который использует Сервис, блокируется на StaticLockObject, но если он действительно берет блокировку, то нет никакой причины делать всю эту двойную проверку блокировки ригамароли вокруг создания и удаления объекта. Следовательно, совершенно очевидно, что этот код является ошибочным.

2 голосов
/ 22 апреля 2011

Это ошибка в движке анализа кода ReSharper 5.X. Исправлено в ReSharper 6.0.

Кстати, ReSharper 6 предлагает больше инструментов для анализа паттернов с двойной блокировкой:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...