Wat doet een slotverklaring onder de motorkap?

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.Enterdoet hier. Om MSDN te citeren:

Gebruik Enterom de Monitor te verkrijgen op
het object doorgegeven als de parameter. Indien
een andere thread heeft een Enteruitgevoerd
op het object maar is nog niet uitgevoerd
de bijbehorende Exit, de huidige
draad zal blokkeren tot de andere
draad geeft het object vrij. Het is
legaal om dezelfde thread aan te roepen
Entermeerdere 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.Entermethode zal oneindig wachten; het zal geentime-out hebben.


Antwoord 2, autoriteit 65%

Het is eenvoudiger dan je denkt-

Volgens Microsoft:
Het sleutelwoord lockzorgt 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 locktrefwoord roept Enteraan het begin van het blok en Exitaan het einde van het blok. locktrefwoord verwerkt eigenlijk Monitorklas 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 objvergrendeld. Wanneer een andere thread probeert binnen te komen, zal deze ook proberen objte vergrendelen, die al is vergrendeld door de eerste thread. De tweede thread zal moeten wachten tot de eerste thread objvrijgeeft. Wanneer de eerste thread verlaat, zal een andere thread objvergrendelen 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 Enteren 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

Other episodes