Kiedy jest właściwe użycie Monitor
klasy lub lock
słowa kluczowego dla bezpieczeństwa wątków w C #?
EDYCJA:
Z dotychczasowych odpowiedzi wynika, że lock
jest to krótka ręka na serię wezwań do Monitor
klasy. Do czego dokładnie służy krótka ręka blokady? Albo bardziej wyraźnie,
class LockVsMonitor
{
private readonly object LockObject = new object();
public void DoThreadSafeSomethingWithLock(Action action)
{
lock (LockObject)
{
action.Invoke();
}
}
public void DoThreadSafeSomethingWithMonitor(Action action)
{
// What goes here ?
}
}
Aktualizacja
Dziękuję wszystkim za pomoc: wysłałem kolejne pytanie w związku z niektórymi podanymi przez was informacjami. Ponieważ wydaje się, że jesteś dobrze zorientowany w tej dziedzinie, opublikowałem link: Co jest złego w tym rozwiązaniu do blokowania i zarządzania zablokowanymi wyjątkami?
lock
bloku.Pulse
prostego blokowania. Jest to ważne w niektórych zaawansowanych scenariuszach wielowątkowości. Nigdy nie korzystałemPulse
bezpośrednio.lock
jest po prostu skrótem doMonitor.Enter
ztry
+finally
iMonitor.Exit
. Używaj instrukcji lock, kiedy tylko jest to wystarczające - jeśli potrzebujesz czegoś takiego jak TryEnter, będziesz musiał użyć Monitora.źródło
Instrukcja lock jest równoważna z:
Monitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
Należy jednak pamiętać, że Monitor może również Wait () i Pulse () , które są często przydatne w złożonych sytuacjach wielowątkowych.
Aktualizacja
Jednak w C # 4 jest inaczej zaimplementowany:
bool lockWasTaken = false; var temp = obj; try { Monitor.Enter(temp, ref lockWasTaken); //your code } finally { if (lockWasTaken) Monitor.Exit(temp); }
Podziękowania dla CodeInChaos za komentarze i linki
źródło
Monitor
jest bardziej elastyczny. Moim ulubionym przypadkiem użycia monitora jest sytuacja, gdy nie chcesz czekać na swoją kolej i po prostu pomiń ://already executing? forget it, lets move on if(Monitor.TryEnter(_lockObject)) { //do stuff; Monitor.Exit(_lockObject); }
źródło
Jak powiedzieli inni,
lock
jest „równoważne” zMonitor.Enter(object); try { // Your code here... } finally { Monitor.Exit(object); }
Ale tylko z ciekawości,
lock
zachowa pierwsze przekazane do niego odniesienie i nie wyrzuci, jeśli je zmienisz. Wiem, że nie zaleca się zmiany zablokowanego obiektu i nie chcesz tego robić.Ale znowu, dla nauki, to działa dobrze:
var lockObject = ""; var tasks = new List<Task>(); for (var i = 0; i < 10; i++) tasks.Add(Task.Run(() => { Thread.Sleep(250); lock (lockObject) { lockObject += "x"; } })); Task.WaitAll(tasks.ToArray());
... a to nie oznacza:
var lockObject = ""; var tasks = new List<Task>(); for (var i = 0; i < 10; i++) tasks.Add(Task.Run(() => { Thread.Sleep(250); Monitor.Enter(lockObject); try { lockObject += "x"; } finally { Monitor.Exit(lockObject); } })); Task.WaitAll(tasks.ToArray());
Błąd:
Dzieje się tak, ponieważ
Monitor.Exit(lockObject);
będzie działać zgodnie zlockObject
tym, co się zmieniło, ponieważstrings
są niezmienne, wtedy wywołujesz go z niezsynchronizowanego bloku kodu ... ale tak czy inaczej. To po prostu zabawny fakt.źródło
object temp = lockObject; Monitor.Enter(temp); <...locked code...> Monitor.Exit(temp);
Obie są tym samym. lock jest słowem kluczowym cisre i użyj klasy Monitor.
http://msdn.microsoft.com/en-us/library/ms173179(v=vs.80).aspx
źródło
Blokada i podstawowe zachowanie monitora (wejście + wyjście) są mniej więcej takie same, ale monitor ma więcej opcji, które pozwalają na większe możliwości synchronizacji.
Blokada jest skrótem i jest opcją do podstawowego zastosowania.
Jeśli potrzebujesz większej kontroli, monitor jest lepszą opcją. Możesz użyć Wait, TryEnter i Pulse, do zaawansowanych zastosowań (takich jak bariery, semafory i tak dalej).
źródło
Słowo kluczowe Lock Lock zapewnia, że jeden wątek wykonuje jednocześnie fragment kodu.
lock (lockObject)
{ // Body }
Słowo kluczowe lock oznacza blok instrukcji jako sekcję krytyczną poprzez uzyskanie blokady wzajemnego wykluczania dla danego obiektu, wykonanie instrukcji, a następnie zwolnienie blokady
Jeśli inny wątek spróbuje wprowadzić zablokowany kod, będzie czekał, blokuje się, aż obiekt zostanie zwolniony.
Monitor Monitor jest klasą statyczną i należy do przestrzeni nazw System.Threading.
Zapewnia wyłączną blokadę obiektu, dzięki czemu tylko jeden wątek może wejść do krytycznej sekcji w danym momencie.
Różnica między monitorem a blokadą w języku C #
Blokada jest skrótem do Monitora, wprowadź spróbuj i na koniec. Zablokuj uchwyty spróbuj i ostatecznie zablokuj wewnętrznie Zablokuj = Monitor + spróbuj w końcu.
Jeśli chcesz mieć większą kontrolę w celu wdrożenia zaawansowanych rozwiązań wielowątkowymi użyciu
TryEnter()
Wait()
,Pulse()
orazPulseAll()
metod, a następnie klasa Monitor jest twój wybór.C #
Monitor.wait()
: Wątek czeka na powiadomienie innych wątków.Monitor.pulse()
: Wątek powiadamia inny wątek.Monitor.pulseAll()
: Wątek powiadamia wszystkie inne wątki w procesieźródło
Oprócz wszystkich powyższych wyjaśnień, lock jest instrukcją C #, podczas gdy Monitor to klasa .NET znajdująca się w przestrzeni nazw System.Threading.
źródło