Ik zie dat voor het gebruik van objecten die niet draadveilig zijn, we de code met een slot als volgt omwikkelen:
private static readonly Object obj = new Object();
lock (obj)
{
// thread unsafe code
}
Dus, wat gebeurt er als meerdere threads toegang krijgen tot dezelfde code (laten we aannemen dat deze wordt uitgevoerd in een ASP.NET-webtoepassing). Staan ze in de rij? Zo ja, hoe lang zullen ze wachten?
Wat is de prestatie-impact door het gebruik van sloten?
Antwoord 1, autoriteit 100%
De lock
-instructie is vertaald door C# 3.0 naar het volgende:
var temp = obj;
Monitor.Enter(temp);
try
{
// body
}
finally
{
Monitor.Exit(temp);
}
In C# 4.0 is dit veranderden het wordt nu als volgt gegenereerd:
bool lockWasTaken = false;
var temp = obj;
try
{
Monitor.Enter(temp, ref lockWasTaken);
// body
}
finally
{
if (lockWasTaken)
{
Monitor.Exit(temp);
}
}
Je kunt meer informatie vinden over wat Monitor.Enter
doet hier. Om MSDN te citeren:
Gebruik
Enter
om de Monitor te verkrijgen op
het object doorgegeven als de parameter. Indien
een andere thread heeft eenEnter
uitgevoerd
op het object maar is nog niet uitgevoerd
de bijbehorendeExit
, de huidige
draad zal blokkeren tot de andere
draad geeft het object vrij. Het is
legaal om dezelfde thread aan te roepen
Enter
meerdere keren in zonder dit
blokkeren; echter een gelijk aantal
Exit
-oproepen moeten eerder worden aangeroepen
andere threads wachten op het object
zal deblokkeren.
De Monitor.Enter
methode zal oneindig wachten; het zal geentime-out hebben.
Antwoord 2, autoriteit 65%
Het is eenvoudiger dan je denkt-
Volgens Microsoft:
Het sleutelwoord lock
zorgt ervoor dat de ene thread niet een kritiek gedeelte van de code binnengaat terwijl een andere thread zich in de kritieke sectie bevindt. Als een andere thread een vergrendelde code probeert in te voeren, zal deze wachten, blokkeren, totdat het object wordt vrijgegeven.
Het lock
trefwoord roept Enter
aan het begin van het blok en Exit
aan het einde van het blok. lock
trefwoord verwerkt eigenlijk Monitor
klas aan de achterkant.
Bijvoorbeeld:
private static readonly Object obj = new Object();
lock (obj)
{
// critical section
}
In de bovenstaande code komt de thread eerst in een kritieke sectie en vervolgens wordt obj
vergrendeld. Wanneer een andere thread probeert binnen te komen, zal deze ook proberen obj
te vergrendelen, die al is vergrendeld door de eerste thread. De tweede thread zal moeten wachten tot de eerste thread obj
vrijgeeft. Wanneer de eerste thread verlaat, zal een andere thread obj
vergrendelen en de kritieke sectie binnengaan.
Antwoord 3, autoriteit 11%
Nee, ze staan niet in de wachtrij, ze slapen
Een slotverklaring van het formulier
lock (x) ...
waarbij x een uitdrukking is van een referentietype, is precies gelijk aan
var temp = x;
System.Threading.Monitor.Enter(temp);
try { ... }
finally { System.Threading.Monitor.Exit(temp); }
Je hoeft alleen maar te weten dat ze op elkaar wachten, en er zal maar één thread binnenkomen om het blok te vergrendelen, de anderen zullen wachten…
Monitor is volledig in .net geschreven, dus snel genoeg, kijk ook op klassenmonitormet reflectorvoor meer details
Antwoord 4, autoriteit 7%
Locks zal voorkomen dat andere threads de code in het lock-blok uitvoeren. De threads zullen moeten wachten tot de thread in het slotblok is voltooid en het slot wordt vrijgegeven. Dit heeft wel een negatieve invloed op de prestaties in een multithreaded omgeving. Als u dit toch moet doen, moet u ervoor zorgen dat de code in het slotblok zeer snel kan worden verwerkt. Probeer dure activiteiten zoals toegang tot een database enz. te vermijden.
Antwoord 5, autoriteit 2%
De impact op de prestaties hangt af van de manier waarop u vergrendelt. Je kunt hier een goede lijst met optimalisaties vinden: http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/
In principe moet je proberen zo min mogelijk te vergrendelen, omdat het je wachtcode in de sluimerstand zet. Als je zware berekeningen of langdurige code (bijv. bestandsupload) in een slot hebt, resulteert dit in een enorm prestatieverlies.
Antwoord 6, autoriteit 2%
Het deel binnen de lock-instructie kan slechts door één thread worden uitgevoerd, dus alle andere threads zullen voor onbepaalde tijd wachten totdat de thread met de lock is voltooid. Dit kan resulteren in een zogenaamde deadlock.
Antwoord 7, autoriteit 2%
De lock
-instructie wordt vertaald naar aanroepen van de Enter
en Exit
-methoden van Monitor
.
De lock
-instructie zal voor onbepaalde tijd wachten tot het vergrendelingsobject wordt vrijgegeven.
Antwoord 8
slotis eigenlijk verborgen Monitor-klasse.
Antwoord 9
Volgens MSDN van Microsoft, het slot is gelijk aan:
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
Als u vergrendelingen in runtime moet maken, kunt u open source DynaLockgebruiken. U kunt tijdens runtime nieuwe vergrendelingen maken en grenzen aan de vergrendelingen specificeren met contextconcept.
DynaLock is open-source en de broncode is beschikbaar op GitHub