Innymi słowy, czy ten wątek implementacyjny Singleton jest bezpieczny:
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
źródło
źródło
Instance
jednocześnie. Jeden z wątków zostanie poproszony o uruchomienie inicjatora typu (znanego również jako konstruktor statyczny). W międzyczasie wszystkie inne wątki, które chcą odczytaćInstance
właściwość, zostaną zablokowane do momentu zakończenia inicjalizacji typu. Dopiero po zakończeniu inicjalizacji pola wątki będą mogły uzyskaćInstance
wartość. Więc nikt nie widziInstance
bytunull
.X
kończą się-1
nawet bez wątków . To nie jest kwestia bezpieczeństwa wątków. Zamiast tego inicjatorx = -1
uruchamia się pierwszy (znajduje się we wcześniejszym wierszu kodu, niższym numerze wiersza). Następnie uruchamia się inicjalizatorX = GetX()
, dzięki czemu wielkie litery sąX
równe-1
. Następnie uruchamianystatic C() { ... }
jest „jawny” konstruktor statyczny, inicjalizator typu , który zmienia tylko małe literyx
. Po tym wszystkimMain
metoda (lubOther
metoda) może kontynuować i czytać wielkie literyX
. Jego wartość będzie-1
, nawet z jednym wątkiem.Odpowiedzi:
Gwarantuje się, że statyczne konstruktory są uruchamiane tylko raz na domenę aplikacji, przed utworzeniem instancji klasy lub dostępem do elementów statycznych. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors
Przedstawiona implementacja jest wątkowo bezpieczna dla początkowej konstrukcji, to znaczy, nie jest wymagane blokowanie ani testowanie zerowe do budowy obiektu Singleton. Nie oznacza to jednak, że wszelkie użycie instancji zostanie zsynchronizowane. Można to zrobić na wiele sposobów; Pokazałem jeden poniżej.
źródło
Lazy<T>
- każdy, kto używa kodu, który pierwotnie opublikowałem, robi to źle (i szczerze mówiąc, początkowo nie było tak dobrze - 5 lat temu - ja nie byłem tak dobry w takich sprawach jak obecnie -me is :)).Chociaż wszystkie te odpowiedzi dają tę samą ogólną odpowiedź, jest jedno zastrzeżenie.
Pamiętaj, że wszystkie potencjalne pochodne klasy ogólnej są zestawiane jako poszczególne typy. Dlatego należy zachować ostrożność przy wdrażaniu konstruktorów statycznych dla typów ogólnych.
EDYTOWAĆ:
Oto demonstracja:
W konsoli:
źródło
Korzystanie z konstruktora statycznego jest w rzeczywistości bezpieczne dla wątków. Konstruktor statyczny może zostać wykonany tylko raz.
Ze specyfikacji języka C # :
Więc tak, możesz ufać, że twój singleton zostanie poprawnie utworzony.
Zooba doskonale podkreśliła (i 15 sekund przede mną!), Że statyczny konstruktor nie gwarantuje bezpiecznego wątku wspólnego dostępu do singletonu. Trzeba to potraktować w inny sposób.
źródło
Oto wersja Cliffnotes z powyższej strony MSDN na c # singleton:
Użyj następującego wzoru, zawsze nie możesz się pomylić:
Poza oczywistymi funkcjami singletonu, daje ci te dwie rzeczy za darmo (w odniesieniu do singletonu w c ++):
źródło
Konstruktory statyczne mają gwarancję, że będą uruchamiane tylko raz na domenę aplikacji, więc twoje podejście powinno być OK. Jednak funkcjonalnie nie różni się od bardziej zwięzłej, wbudowanej wersji:
Bezpieczeństwo wątków jest większym problemem, gdy leniwie inicjujesz różne rzeczy.
źródło
Konstruktor statyczny zakończy działanie wcześniej dowolny wątek dostęp do klasy.
Powyższy kod wygenerował poniższe wyniki.
Mimo że statyczny konstruktor długo działał, pozostałe wątki zatrzymały się i czekały. Wszystkie wątki odczytują wartość _x ustawioną na dole konstruktora statycznego.
źródło
Specyfikacja Common Language Infrastructure gwarantuje, że „inicjalizator typu będzie uruchamiany dokładnie raz dla każdego typu, chyba że zostanie wyraźnie wywołany przez kod użytkownika”. (Sekcja 9.5.3.1.) Jeśli więc nie masz jakiejś zwariowanej IL na luźnym wywołaniu Singleton ::. Cctor bezpośrednio (mało prawdopodobne), twój konstruktor statyczny uruchomi się dokładnie raz przed użyciem typu Singleton, zostanie utworzona tylko jedna instancja Singleton, a twoja właściwość Instancji jest bezpieczna dla wątków.
Należy zauważyć, że jeśli konstruktor Singleton uzyskuje dostęp do właściwości Instancji (nawet pośrednio), wówczas właściwość Instancji będzie miała wartość NULL. Najlepsze, co możesz zrobić, to wykryć, kiedy to nastąpi, i zgłosić wyjątek, sprawdzając, czy instancja nie ma wartości NULL w module dostępu do właściwości. Po zakończeniu konstruktora statycznego właściwość Instancja będzie inna niż null.
Jak wskazuje odpowiedź Zoomba, będziesz musiał zapewnić Singletonowi bezpieczny dostęp z wielu wątków lub zaimplementować mechanizm blokujący za pomocą instancji singletonu.
źródło
Po prostu pedantyczny, ale nie ma czegoś takiego jak konstruktor statyczny, ale raczej inicjatory typu statycznego, oto mała demonstracja zależności cyklicznego konstruktora statycznego, która ilustruje ten punkt.
źródło
Konstruktor statyczny gwarantuje bezpieczeństwo wątków. Zapoznaj się także z dyskusją na temat Singleton na stronie DeveloperZen: http://web.archive.org/web/20160404231134/http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code -1-dyskusja /
źródło
Chociaż inne odpowiedzi są w większości poprawne, istnieje jeszcze jedno zastrzeżenie dotyczące konstruktorów statycznych.
Zgodnie z § II.10.5.3.3 ras i zakleszczenia na Infrastruktury ECMA-335 wspólny język
Poniższy kod powoduje zakleszczenie
Oryginalnym autorem jest Igor Ostrovsky, zobacz jego post tutaj .
źródło