Какие опасности использования синглтона в многопоточном приложении

Я смотрю на использование синглтона в многопоточном сервисе Win для ведения журнала и хотел бы знать, с какими проблемами я могу столкнуться. Я уже настроил экземпляр get для обработки синхронизации с

    private static volatile Logging _instance;
    private static object _syncRoot = new object();

    private Logging(){}
    public static Logging Instance
    {
        get
        {
            if (_instance==null)
            {
                lock(_syncRoot)
                {
                    if (_instance == null)
                    {
                        _instance = new Logging();
                    }
                }
            }
            return _instance;
        }
    }

есть ли что-нибудь еще, о чем мне нужно беспокоиться?

8 ответов


Это выглядит довольно хорошо для меня.

посмотреть реализует паттерн Singleton в C# для получения дополнительной информации.

Edit: вероятно, следует поместить возврат внутрь замка.


Это более информативно, чем что-либо еще.

то, что вы опубликовали, это дважды проверенный алгоритм блокировки - и что ты написал будет работа, насколько мне известно. (Начиная с Java 1.5 он работает и там.) Тем не менее, это очень хрупко - если вы немного ошибетесь, вы можете ввести очень тонкие условия гонки.

обычно я предпочитаю инициализировать синглтон в статическом инициализаторе:

public class Singleton
{
    private static readonly Singleton instance = new Singleton();

    public static Singleton Instance
    {
        get { return instance; }
    }

    private Singleton()
    {
        // Do stuff
    }
}

(добавление статический конструктор, если вы хотите немного лень.)

этот шаблон легче получить правильно, и в большинстве случаев это так же хорошо.

там больше деталей на моем страница реализации C# singleton (также связано Майклом).

что касается опасностей - я бы сказал, что самая большая проблема заключается в том, что вы теряете тестируемость. Наверное, нет!--4-->слишком плохо для ведения журнала.


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

в этом случае это может быть неплохо, потому что вы не хотите, чтобы несколько элементов записывались в ваш файл одновременно, и даже поэтому я не думаю, что ваша реализация будет иметь такой результат. Но это нечто, о чем нужно знать.


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


вы используете двойная проверка блокировки что считается анти-паттерн. Википедия имеет шаблоны с ленивой инициализацией и без нее для разных языков.

после создания экземпляра singleton вы, конечно, должны убедиться, что все методы потокобезопасны.


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

другой вариант, который у вас есть, - использовать систему.Нарезка резьбы.Сблокированный.CompareExchange (T%, T, T) : метод T для переключения. Это менее запутанно и гарантированно работает.

System.Threading.Interlocked.CompareExchange<Logging>(_instance, null, new Logging());

есть некоторые дебаты относительно необходимости сделать первую проверку для потока использования null.VolatileRead () если вы используете шаблон блокировки с двойной проверкой и хотите, чтобы он работал на всех моделях памяти. Пример дискуссии можно прочитать на http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/b1932d46-877f-41f1-bb9d-b4992f29cedc/.

тем не менее, я обычно использую решение Джона Скита сверху.


Я думаю, что если методы экземпляра журнала потокобезопасны, беспокоиться не о чем.