Wersja C # zsynchronizowanego słowa kluczowego Java?

313

Czy c # ma własną wersję słowa kluczowego „synchronizowane” java?

Tj. W java można określić funkcję, obiekt lub blok kodu, na przykład:

public synchronized void doImportantStuff() {
   // dangerous code goes here.
}

lub

public void doImportantStuff() {
   // trivial stuff

   synchronized(someLock) {
      // dangerous code goes here.
   }
}
Soraz
źródło
3
Formularz bloku wymaga odniesienia do blokady. W formularzu metody obiekt blokady jest domyślnie tym (lub klasą [this.class, nie getClass ()] dla metod statycznych, ale nie blokuje na klasach).
Tom Hawtin - tackline
1
Nadal nie jesteś chroniony? Zawsze tu przychodzę, bo nie pamiętam tej [MethodImpl(MethodImplOptions.Synchronized)]linii.
Bitterblue,
1
Myślę, że Twój drugi fragment kodu nie skompiluje się - musi być zsynchronizowany z czymś.
PoweredByRice

Odpowiedzi:

466

Po pierwsze - większość klas nigdy nie musi być bezpieczna dla wątków. Używaj YAGNI : stosuj zabezpieczenie wątków tylko wtedy, gdy wiesz, że faktycznie zamierzasz go użyć (i przetestować).

Dla rzeczy na poziomie metod jest [MethodImpl]:

[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}

Można tego również użyć w akcesoriach (właściwościach i zdarzeniach):

private int i;
public int SomeProperty
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get { return i; }
    [MethodImpl(MethodImplOptions.Synchronized)]
    set { i = value; }
}

Pamiętaj, że zdarzenia podobne do pól domyślnie synchronizowane, a właściwości zaimplementowane automatycznie nie są :

public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized

Osobiście nie lubię implementacji, MethodImplponieważ blokuje thislub typeof(Foo)- co jest sprzeczne z najlepszymi praktykami. Preferowaną opcją jest użycie własnych zamków:

private readonly object syncLock = new object();
public void SomeMethod() {
    lock(syncLock) { /* code */ }
}

Należy zauważyć, że w przypadku zdarzeń podobnych do pola implementacja blokowania zależy od kompilatora; w starszych kompilatorach Microsoft jest to lock(this)/ lock(Type)- jednak w nowszych kompilatorach używaInterlocked aktualizacji - więc jest bezpieczne dla wątków bez nieprzyjemnych części.

Pozwala to na bardziej szczegółowe użycie i umożliwia użycie Monitor.Wait/ Monitor.Pulseetc do komunikacji między wątkami.

Powiązany wpis na blogu (później ponownie odwiedzony ).

Marc Gravell
źródło
@earcam, a twoje pytanie brzmi? To stwierdzenie jest prawdziwe. Zdecydowana większość zajęć nie ma wymogu, by być bezpieczny wątku, nie będą testowane na wątku bezpieczeństwa i posiadające wątku bezpieczeństwa wpłynie na wydajność. Liczba typów, które naprawdę muszą się martwić o wątki, jest bardzo mała - celowo zsynchronizowane kolekcje, multipleksery itp.
Marc Gravell
4
Myślę, że powinienem po prostu powiedzieć; „większość klas nigdy nie będzie musiała być bezpieczna dla wątków”, ale „wszyscy programiści muszą mieć świadomość współbieżności”. Z perspektywy czasu zgadzam się, że liczba ta jest bardzo mała (i zdecydowanie coś, co chcesz uzyskać raz w jednym miejscu, pozwalając większości klasom na interakcję, nie zwracając uwagi na ich wielowątkowe otoczenie). Chciałbym szybciej usunąć komentarz =)
kamera douszna
6
Powiązany post Marca na blogu zawiera kontynuację z marca 2010 r., Mówiącą , że w .NET 4.0 MethodImplzdarzenia podobne do pola generują teraz dobry kod synchronizacji i nie trzeba już używać własnych blokad.
Rory O'Kane
2
Zdecydowana większość aplikacji jest obecnie oparta na sieci Web, obsługiwana w ramach opartych na wielokrotnym użyciu instancji i cyklu życia złożonych obiektów poprzez wstrzykiwanie zależności. Domyślny sposób myślenia w dzisiejszych czasach ma tendencję do bycia po stronie bezpieczeństwa wątków.
Sheepy,
1
@Elazar jest już za późno, ale dla przypomnienia: zmiana frameworku jest zmianą jednowierszową dla nich csproj, jeśli utworzyłeś go przy użyciu standardowych szablonów .net / core .NET - i jest dostępny zwykły .net, podobnie jak wiele -kierowanie. Jednak oprzyrządowanie do tego IDE jest po prostu okropne - wystarczy wiedzieć, co możesz zmienić i do czego :)
Marc Gravell
57
static object Lock = new object();

lock (Lock) 
{
// do stuff
}
Jan Gressmann
źródło
9
Czy na pewno chcesz zadeklarować obiekt blokady jako statyczny?
serg10
21
Jasne, aby każdy wątek miał łatwy dostęp do niego bez przekazywania referencji.
Jan Gressmann
32
Jeśli jesteśmy w kontekście pytania pytającego, to mówimy o metodach instancji. Użycie statycznego oznacza, że ​​jeśli wątek 1 wywoła instancję 1.DoSomething (), a wątek 2 wywoła instancję 2.DoSomething, drugie wywołanie zostanie zablokowane, nawet jeśli jest to zupełnie inny obiekt. Wywołanie Thread2 nie powinno blokować, chyba że ktoś wywoła DoSomething na tym samym obiekcie . Nie mówię, że się mylisz, ale mówisz, że ważne jest, aby zrozumieć efekt użycia static tutaj, ponieważ może to powodować niską wydajność, blokując globalnie zamiast na podstawie poszczególnych instancji.
AaronLS,
1
@AaronLS Blokada statyczna, jeśli bardzo przydatna, gdy obiekt wykonuje działania w większym zakresie niż on sam. Zawsze dzieje się tak na przykład w przypadku usług internetowych.
Thibault D.
3
-1, ponieważ jest to inne zachowanie, niż wymaga PO. To jest blokada klasy, a nie blokada instancji.
tster,
39

Czy c # ma własną wersję słowa kluczowego „synchronizowane” java?

Nie. W języku C # jawnie lockzasoby, na których chcesz pracować synchronicznie między wątkami asynchronicznymi. lockotwiera blok; nie działa na poziomie metody.

Jednak podstawowy mechanizm jest podobny, ponieważ lockdziała poprzez wywołanie Monitor.Enter(a następnie Monitor.Exit) w środowisku wykonawczym. Java działa w ten sam sposób, zgodnie z dokumentacją Sun .

Konrad Rudolph
źródło
3
Nie ma równoważnego „słowa kluczowego”, ale jak pokazuje powyższa odpowiedź Marc Gravell, możesz synchronizować na poziomie metody za pomocą adnotacji [MethodImpl (MethodImplOptions.Synchronized)].
MindJuice
1
Ponieważ synchronizedmetoda Java w zasadzie synchronized (this.getClass())nie jest podobna na C # lock(typeof(this))?
Sri Harsha Chilakapati
2
@SriHarshaChilakapati, które jest tylko częściowo poprawne, synchronizedsłowo kluczowe java w metodzie jest bardziej podobne: synchronized(this)tylko w metodzie statycznej zachowuje się jak synchronized(class).
bvdb,
7

Zwróć uwagę, z pełnymi ścieżkami linia: [MethodImpl(MethodImplOptions.Synchronized)]powinna wyglądać

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]

Traubenfuchs
źródło
1
lub możesz po prostu użyćusing System.Runtime.CompilerServices;
aloisdg przeprowadza się do codidact.com
Napisałem ten komentarz, kiedy jeszcze nie wiedziałem o automatycznym wstawianiu za pomocą instrukcji, po zaprogramowaniu C # na nie więcej niż kilka dni lub tygodni i jestem zdumiony tymi 3 pozytywnymi opiniami.
Traubenfuchs,
1
Pomogłeś
5

Zamiast tego możesz użyć lockinstrukcji. Myślę, że to może zastąpić tylko drugą wersję. Należy również pamiętać, że zarówno synchronizedi locktrzeba działać na obiekcie.

James
źródło