ASP.NET Threading - двойная проверка блокировки

2

У меня есть метод расширения объекта HttpApplicationState для получения моего контейнера IoC из приложения. Этот же код также создаст контейнер, если он не существует.

У меня есть 2 вопроса:

  • Я действительно ли мой код потокобезопасен, поскольку я намерен его
  • Это считается лучшей практикой для работы с состоянием приложения.

Введите код следующим образом:

private const string GlobalContainerKey = "UnityContainerKey";

public static IUnityContainer GetContainer(this HttpApplicationState application)
{
    var container = application[GlobalContainerKey] as IUnityContainer;

    if (container == null)
    {
        try
        {
            application.Lock();
            container = application[GlobalContainerKey] as IUnityContainer;

            if (container == null)
            {
                container = new UnityContainer();
                application[GlobalContainerKey] = container;
            }
        }
        finally
        {
            application.UnLock();
        }
    }

    return container;
}
  • 0
    Кроме того, я сделал весь этот вопрос бессмысленным, так как я перешел с Unity на StructureMap, и SM представляет себя как статический класс, поэтому мне никогда не нужно беспокоиться о том, что он не существует.
Теги:
multithreading

4 ответа

3
Лучший ответ

Вам нужно поставить

var container = application[GlobalContainerKey] as IUnityContainer;

в замке, в противном случае многие потоки могут последовательно создавать новый контейнер.

private const string GlobalContainerKey = "UnityContainerKey";
private const object lockObject = new object();

public static IUnityContainer GetContainer(this HttpApplicationState application)
{
    var IUnityContainer container = null;

    lock (lockObject)
    {
        container = application[GlobalContainerKey] as IUnityContainer;
        if (container == null)
        {
            container = new UnityContainer();
            application[GlobalContainerKey] = container;
        }
    }

    return container;
}
  • 0
    Вы правы, я хотел, чтобы это было внутри перед вторым оператором if.
  • 0
    Нет необходимости во втором операторе if, если первый находится в замке. Также, если вы используете lock (), вам не понадобится try / finally (lock () - это синтаксический сахар для try / finally.
Показать ещё 4 комментария
1

Двойная проверка с помощью блокировки используется внутри кода .NET Framework для одиночных (например, System.Web.Profile.ProfileManager).

Итак, я думаю, что ваша реализация в порядке.

1

Почему вы впервые проверяете "container == null"? Я думаю, вы должны сначала заблокировать, а затем проверить, что контейнер равен null. Всевозможные хитроумные вещи могут произойти между первым if и return в других потоках.

  • 0
    Я не хочу блокировать приложение каждый раз после того, как контейнер существует, потому что это вызывается при каждом запросе страницы. Он должен быть заблокирован только для начальной вставки. Однако я хотел иметь второй "container = application [GlobalContainerKey] как IUnityContainer;" после блокировки
1

Технически это не будет работать с учетом спецификации EMCA. Джон Скит рассказывает об этом в своем FAQ на С#:

http://www.yoda.arachsys.com/csharp/singleton.html

В частности, см. раздел с "Третьей версией"

Я хотел бы прочитать дальше и использовать его предложение о том, как реализовать синглтон, чтобы понять, как реализовать то, что вы пытаетесь сделать.

  • 0
    Разница в том, что я уже работаю с синглтоном, а не пытаюсь создать новый синглтон. Чтение пункта 2 в его обосновании против DCL является единственной законной точкой, однако нет никакой детализации, почему это не сработает или что "явные вызовы барьера памяти" должны были бы обеспечить это.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню