Другими словами, безопасен ли этот поток реализации Singleton:
public class Singleton
{
private static Singleton instance;
private Singleton() { }
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance
{
get { return instance; }
}
}
c#
multithreading
singleton
urini
источник
источник
Instance
одновременно. Один из потоков получит команду сначала запустить инициализатор типа (также известный как статический конструктор). Между тем все остальные потоки, желающие прочитатьInstance
свойство, будут заблокированы до завершения инициализатора типа. Только после завершения инициализации поля потокам будет разрешено получитьInstance
значение. Так что никто не может видетьInstance
бытиеnull
.X
получается-1
даже без многопоточности . Это не проблема безопасности потоков. Вместо этого инициализаторx = -1
запускается первым (он находится на более ранней строке в коде, номер нижней строки). ЗатемX = GetX()
запускается инициализатор , что делает верхний регистрX
равным-1
. Затемstatic C() { ... }
запускается «явный» статический конструктор, инициализатор типа , который изменяется только в нижнем регистреx
. Таким образом, после всего этогоMain
метод (илиOther
метод) может продолжаться и читать в верхнем регистреX
. Его значение будет-1
, даже с одним потоком.Ответы:
Статические конструкторы гарантированно будут запускаться только один раз в домене приложения до создания каких-либо экземпляров класса или доступа к любым статическим членам. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
Показанная реализация является поточно-ориентированной для начальной конструкции, то есть для создания объекта Singleton не требуется блокировка или нулевое тестирование. Однако это не означает, что любое использование экземпляра будет синхронизировано. Существует множество способов сделать это; Я показал один ниже.
источник
Lazy<T>
- любой, кто использует код, который я первоначально разместил, делает это неправильно (и, честно говоря, это было не так хорошо для начала - 5 лет назад я не был так хорош в этом, как нынешний -я есть :) ).Хотя все эти ответы дают один и тот же общий ответ, есть одна оговорка.
Помните, что все потенциальные производные универсального класса компилируются как отдельные типы. Поэтому будьте осторожны при реализации статических конструкторов для универсальных типов.
РЕДАКТИРОВАТЬ:
Вот демонстрация:
В консоли:
источник
Использование статического конструктора на самом деле является потокобезопасным. Статический конструктор гарантированно будет выполнен только один раз.
Из спецификации языка C # :
Так что да, вы можете верить, что ваш синглтон будет правильно создан.
Zooba сделал отличное замечание (и за 15 секунд до меня тоже!), Что статический конструктор не гарантирует потокобезопасный общий доступ к синглтону. Это должно быть обработано другим способом.
источник
Вот версия Cliffnotes с указанной выше страницы MSDN на c # singleton:
Всегда используйте следующий шаблон, вы не ошибетесь:
Помимо очевидных синглтон-функций, он дает вам две эти вещи бесплатно (в отношении синглтона в c ++):
источник
Статические конструкторы гарантированно срабатывают только один раз для каждого домена приложения, поэтому ваш подход должен быть в порядке. Тем не менее, он функционально не отличается от более сжатой, встроенной версии:
Безопасность потоков - более важная проблема, когда вы лениво инициализируете вещи.
источник
Статический конструктор завершит работу, прежде чем какой-либо поток сможет получить доступ к классу.
Код выше дал результаты ниже.
Хотя статическому конструктору потребовалось много времени, другие потоки остановились и стали ждать. Все потоки читают значение _x, установленное в нижней части статического конструктора.
источник
Спецификация инфраструктуры общего языка гарантирует, что «инициализатор типа должен запускаться ровно один раз для любого данного типа, если это явно не вызвано кодом пользователя». (Раздел 9.5.3.1.) Таким образом, если у вас нет какого-то дурацкого IL на вызове Singleton ::. Cctor напрямую (маловероятно), ваш статический конструктор будет запущен ровно один раз перед использованием типа Singleton, будет создан только один экземпляр Singleton, и ваше свойство Instance является поточно-ориентированным.
Обратите внимание, что если конструктор Singleton обращается к свойству Instance (даже косвенно), свойство Instance будет иметь значение null. Лучшее, что вы можете сделать, это обнаружить, когда это происходит, и выдать исключение, проверив, что экземпляр не равен NULL в методе доступа к свойству. После завершения статического конструктора свойство Instance будет иметь ненулевое значение.
Как указывает ответ Zoomba , вам нужно сделать Singleton безопасным для доступа из нескольких потоков или внедрить механизм блокировки с использованием экземпляра singleton.
источник
Просто чтобы быть педантичным, но нет такого понятия, как статический конструктор, а есть статические инициализаторы типов, вот небольшая демонстрация циклической статической зависимости конструктора, которая иллюстрирует этот момент.
источник
Статический конструктор гарантированно безопасен для потоков. Также ознакомьтесь с обсуждением Singleton на DeveloperZen: http://web.archive.org/web/20160404231134/http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code -1-обсуждение /
источник
Хотя другие ответы в основном правильные, есть еще одна оговорка со статическими конструкторами.
Как указано в разделе II.10.5.3.3 Расы и тупиков в инфраструктуре ECMA-335 Common Language
Следующий код приводит к тупику
Оригинальный автор Игорь Островский, смотрите его пост здесь .
источник