Dlaczego obiekt zamka musi być statyczny?

112

Bardzo często używa się prywatnego statycznego obiektu tylko do odczytu do blokowania w wielowątkowości. Rozumiem, że prywatny zmniejsza punkty wejścia do obiektu blokującego poprzez uszczelnienie hermetyzacji, a tym samym dostęp do najistotniejszych.

Ale dlaczego statyczne?

private static readonly object Locker = new object();

Na końcu pole jest używane tylko w mojej klasie, a zamiast tego mógłbym też po prostu użyć tego:

private readonly object Locker = new object();

Jakieś uwagi?

AKTUALIZACJA:

Jako przykład wkleiłem ten kod (tylko przykład). Mógłbym użyć do tego statycznej lub niestatycznej szafki i oba będą działać dobrze. Biorąc pod uwagę odpowiedź poniżej, powinienem raczej zdefiniować moją szafkę w ten sposób? (Przepraszam, że mam wywiad w przyszłym tygodniu i muszę znać każdy szczegół :)

private readonly object Locker = new object();

A oto kod:

    private int _priceA;
    private int _priceB;
    private EventWaitHandle[] _waithandle;
    private readonly IService _service;

//ctor
public ModuleAViewModel(IService service)
    {
        _service = service;
        _modelA = new ModelA();
        _waithandle = new ManualResetEvent[2];
        _waithandle[0] = new ManualResetEvent(false);
        _waithandle[1] = new ManualResetEvent(false);
        LoadDataByThread();
    }


 private void LoadDataByThread()
        {
            new Thread(() =>
                           {
                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceA = _service.GetPriceA();
                                   }
                                   _waithandle[0].Set();
                               }).Start();

                               new Thread(() =>
                               {
                                   lock (Locker)
                                   {
                                       _priceB = _service.GetPriceB();
                                   }
                                   _waithandle[1].Set();
                               }).Start();

                               WaitHandle.WaitAll(_waithandle);
                               PriceA = _priceA;
                               PriceB = _priceB;
                           }).Start();
        }

Dzięki

Houman
źródło
15
O ile mi wiadomo, statyczny jest zwykle używany, aby uczynić go agnostycznym. Jeśli istnieje kilka wystąpień „MyWorkerClass”, tylko jeden może działać z podanymi danymi naraz (zakładając, że wszystkie używają współdzielonych zasobów).
Brad Christie,
2
W edycji brakuje ważnego szczegółu: gdzie są _servicei _waithandleznajdują się? instancja? statyczny? inny? Może to być na przykład celowa synchronizacja dostępu do zdalnego serwera ...
Marc Gravell
racja, z drugą edycją: tak, od tego końca możesz zablokować dla każdej instancji. Nie mogą być powody, aby to statyczne, choć - jeśli oryginalny dev chciał (jak wspomniano), aby uzyskać dostęp zsynchronizować tak, że serwer pobiera tylko jeden wniosek od razu od tego AppDomain ... Nie mogę wiedzieć, czy ma to miejsce w przypadku , czy też był to przypadek.
Marc Gravell

Odpowiedzi:

177

Nie jest „bardzo powszechne używanie prywatnego statycznego obiektu tylko do odczytu do blokowania w wielowątkowości” - raczej często używa się blokady na odpowiednim / wybranym poziomie szczegółowości . Czasami tak jest static. Częściej IMO tak nie jest - ale jest oparte na instancji .

Główny czas, w którym widzisz staticblokadę, dotyczy globalnej pamięci podręcznej lub odroczonego ładowania globalnych danych / singletonów. A w tym ostatnim, że są lepsze sposoby robi to w każdym razie .

Więc to naprawdę zależy: jak jest Lockerużywane w twoim scenariuszu? Czy chroni coś, co samo w sobie jest statyczne? Jeśli tak, zamek powinien być statyczny. Jeśli chroni coś, co jest oparte na instancjach , wówczas blokada IMO powinna również być oparta na instancjach.

Marc Gravell
źródło
24
Czy mógłbyś podać więcej szczegółów na temat lepszego sposobu odroczenia ładowania danych globalnych?
bizi
Zawsze używam static / volatile, ponieważ jeśli istnieje kilka miejsc, w których jest on oparty na instancji, nadal chciałbym kontrolować moją metodę / zmienną, do której można uzyskać dostęp w sposób bezpieczny dla wątków. Wiele instancji może mieć dostęp do tych samych zasobów i chcę to kontrolować. ja też chciałbym zobaczyć, jak to działa lepiej. Masz świetną reputację i jestem pewien, że Twoja odpowiedź będzie dla mnie równie wspaniała. Proszę odpowiedz?
Andrew Simpson,
82

To nie musi być statyczne, w rzeczywistości czasami powinno nie być statyczne.

Zmienna powinna znajdować się w tym samym zakresie, co metody, w których jest używana do blokowania. Jeśli metody są statyczne, zmienna powinna być statyczna, a jeśli metody są metodami instancji, zmienna powinna być zmienną instancji.

Zmienna statyczna będzie nadal działać, gdy zostanie użyta do blokowania w metodzie instancji, ale wtedy będziesz blokować zbyt mocno. Zablokujesz wszystkie metody we wszystkich instancjach, a nie tylko metody w tej samej instancji.

Guffa
źródło
28
+1 dla „a-ha” ... Zablokujesz wszystkie metody we wszystkich instancjach, a nie tylko metody w tej samej instancji.
radarbob
3
@radarbob - Drobny szczegół: nie zablokujesz wszystkich metod , po prostu założysz blokadę, która może być zainteresowana większą liczbą klientów. Metody nigdy nie są blokowane, po prostu został przejęty muteks.
Erno,
Podejrzewam, że sformułowanie tej odpowiedzi może być mylące - blokowanie nie powinno mieć nic wspólnego z zakresem metod - powinno dotyczyć tylko zakresu udostępnianych danych, do których te metody mają dostęp. Metoda instancji może nie uzyskiwać dostępu do żadnych udostępnionych danych (a zatem nie ma potrzeby blokowania), może uzyskiwać dostęp do statycznych udostępnionych danych (i dlatego wymaga statycznej blokady, zamiast tego dobrym pomysłem może być również refaktoryzacja), to samo dla statycznych ...
Alexei Levenkov
@AlexeiLevenkov: Masz rację, że zakres powinien być tak naprawdę ustalany na podstawie tego, czy dane są statyczne, czy nie, ale zakres metod powinien być również określony na podstawie tego, więc wszystko pasuje do siebie. Dane instancji zwykle nie wymagają blokowania, ale jeśli instancja jest współużytkowana między wątkami, konieczne będzie zablokowanie.
Guffa
28

Zakres i żywotność blokady może / powinna zależeć od „rzeczy”, którą chcesz zablokować. Blokady statyczne są najczęściej używane do blokowania elementów statycznych.

Eee nie
źródło
3
Drobny szczegół: zamek nie jest statyczny, obiekt używany do identyfikacji blokady jest statyczny. Kolejny drobny szczegół: nie blokujesz „rzeczy”.
Guffa,
2
Tak, myślę, że gdybyśmy spróbowali zamknąć niewłaściwe „rzeczy”, mogą być zbyt duże i mocne i pewnego dnia uciec.
ProfK
12
@Guffa To dziwne, w komentarzu powyżej słusznie powiedziałeś: „Po prostu zbytnio komplikujesz rzeczy”, teraz widzę 1 minutę przed tym, wydaje się, że
Nicholas Petersen