2009-08-13 17 views
7

Powiel możliwe:
Is the C# static constructor thread safe?Inicjalizacja statyczna gwarantuje bezpieczeństwo pojedynczej nici? (C#)

doskonały artykuł

Jon Skeet pod adresem http://csharpindepth.com/Articles/General/Singleton.aspx i inne artykuły czytałem jasno, że zamek double-check nie działa w zarówno C#, jak i Java, chyba że jednoznacznie oznaczy instancję jako "lotną". Jeśli tego nie zrobisz, sprawdzenie porównania z wartością null może zwrócić false, nawet jeśli konstruktor instancji nie został jeszcze uruchomiony. W trzeciej próbie pana Skeeta stwierdza to wyraźnie: "Model pamięci Java nie zapewnia, że ​​konstruktor zakończy pracę, zanim odwołanie do nowego obiektu zostanie przypisane do instancji. Model pamięci Java przeszedł ponowną obróbkę dla wersji 1.5, ale dwukrotnie -blok kontrolny jest nadal łamany po tym bez zmiennej lotnej (jak w C#) "

Jednak większość się zgadza (w tym Pan Skeet, w próbkach czwartych i piątych w swoim artykule), że użycie statycznej inicjalizacji jest prosty sposób na uzyskanie instancji singleton wątku. Stwierdza on, że "konstruktory statyczne w języku C# są określone do wykonania tylko wtedy, gdy instancja klasy jest tworzona lub odwołuje się do elementu statycznego, i do wykonania tylko raz dla każdej AppDomain."

Ma to sens, ale brakuje czegoś, co oznacza, że ​​odniesienie do nowego obiektu jest przypisane dopiero po zakończeniu konstruktora - w przeciwnym razie uzyskalibyśmy ten sam problem, który powoduje, że podwójne sprawdzanie blokowania kończy się niepowodzeniem, chyba że oznaczysz instancję jako niestabilną. Czy istnieje gwarancja, że ​​podczas korzystania z inicjalizacji statycznej do wywołania konstruktora instancji (w przeciwieństwie do wywoływania konstruktora instancji z get {} obiektu, tak jak robimy to z blokadą double-check), konstruktor w pełni zakończy działanie przed dowolnym innym wątkiem można uzyskać odwołanie do obiektu?

Dzięki!

+0

(odpowiedział na komentarz) –

Odpowiedz

2

Tak; gwarancja dotyczy oświadczenia, że ​​będzie wykonywana tylko raz w AppDomain.

Mogłoby być niebezpieczne, gdyby mogło być wykonywane więcej niż jeden raz; jak stwierdzono, nie może, więc wszystko jest dobrze :)

9

że konstruktor będzie w pełni ukończony, zanim jakikolwiek inny wątek może uzyskać odniesienie do obiektu?

Statyczny inicjator zostanie wywołany tylko raz (przez system, co najmniej) za AppDomain oraz w zsynchronizowany sposób, biorąc „beforefieldinit” pod uwagę. Zakładając, że nie zrobisz nic dziwnego, wszelkie statyczne pola przypisane w statycznym inicjalizatorze powinny być w porządku; wszelkie inne próby użycia pola statycznego powinny zostać wstrzymane (zablokowane) za statycznym konstruktorem.

odniesienie do nowego obiektu jest przypisany tylko po konstruktor kończy

Zdarza się, kiedy to się stanie. Każdy inicjalizator pola statycznego zdarza się przed, który typowo myślisz jako konstruktor, na przykład. Ale ponieważ inne wątki są blokowane, nie powinno to stanowić problemu.

Jednakże:

  • jeśli statyczna inicjator sam przechodzi odniesienie zewnątrz (poprzez wywołanie metody z odniesieniem jako argument (w tym „arg0”), wówczas wszystkie zakłady są wyłączone
  • jeśli użyć refleksji do wywołania konstruktora statycznego (tak, można to zrobić), crazyness często następuje
+0

myślę, że odpowiedzi na moje pytanie, ale kilka śledzić wzloty: - Mówisz, że inne wątki są blokowane - tak nie jest w przypadku konstruktorów instancji, zgadza się? W przeciwnym razie problem z blokadą podwójnego sprawdzenia nie istnieje? - Czy możesz wyjaśnić swój pierwszy punktor? Na przykład, jeśli mam statyczny obiekt Dictionary , aw statycznym konstruktorze klasy I "nowy" to, a następnie wywołuję myDict.Add() bazillion razy, aby dodać kilka wpisów, to gwarantuje się, że wszystkie te Dodaj() połączenia zostaną zakończone, zanim jakikolwiek inny wątek może korzystać z myDict? –

+0

2: tak; tak długo, jak dzieje się to w statycznym kodzie, pozostałe wątki powinny być blokowane. W jaki sposób 2 wątki mogą rozmawiać z instancją podczas budowy? –

+0

Zły przykład z mojej strony. Zobacz trzecią próbkę tutaj: http://msdn.microsoft.com/en-us/library/ms998558.aspx. Dopóki nie ustawisz "instancji" na lotną, możliwe, że kompilator wstawia konstruktor, a zmienna o nazwie "instancja" może uzyskać odwołanie * przed * skonstruowaniem obiektu. Inny wątek może zatrzymać tę instancję, powodując, że pierwsze sprawdzenie podwójnego sprawdzenia zwróci false, a następnie ten wątek może skończyć się przy użyciu niezbudowanej instancji. Próbuję ustalić, czy prosty akt korzystania z inicjowania typu całkowicie uniemożliwia to lub coś podobnego. –