635 votes

Que fait une déclaration de verrouillage sous le capot ?

Je vois que pour utiliser des objets qui ne sont pas thread safe, nous entourons le code d'un verrou comme ceci :

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

Alors, que se passe-t-il lorsque plusieurs threads accèdent au même code (supposons qu'il s'exécute dans une application Web ASP.NET). Sont-ils mis en file d'attente ? Si oui, combien de temps vont-ils attendre ?

Quel est l'impact de l'utilisation de verrous sur les performances ?

1 votes

530voto

Steven Points 56939

El lock est traduite par C# 3.0 comme suit :

var temp = obj;

Monitor.Enter(temp);

try
{
    // body
}
finally
{
    Monitor.Exit(temp);
}

En C# 4.0 cela a changé et il est maintenant généré comme suit :

bool lockWasTaken = false;
var temp = obj;
try
{
    Monitor.Enter(temp, ref lockWasTaken);
    // body
}
finally
{
    if (lockWasTaken)
    {
        Monitor.Exit(temp); 
    }
}

Vous pouvez trouver plus d'informations sur ce que Monitor.Enter fait ici . Pour citer MSDN :

Utilice Enter pour acquérir le Moniteur sur l'objet passé en paramètre. Si un autre thread a exécuté un Enter sur l'objet mais n'a pas encore exécuté l'opération correspondante Exit le courant actuel bloquera jusqu'à ce que l'autre l'autre thread libère l'objet. Il est légal pour le même thread d'invoquer Enter plus d'une fois sans elle blocage ; cependant, un nombre égal de Exit doivent être invoqués avant que les appels les autres threads en attente sur l'objet se débloquent.

El Monitor.Enter attendra infiniment ; elle pas temps mort.

26 votes

Selon MSDN, "l'utilisation du mot-clé lock (C#) ou SyncLock (Visual Basic) est généralement préférable à l'utilisation directe de la classe Monitor, à la fois parce que lock ou SyncLock est plus concis et parce que lock ou SyncLock garantit que le moniteur sous-jacent est libéré, même si le code protégé lève une exception. Ceci est accompli avec le mot-clé finally, qui exécute son bloc de code associé, qu'une exception soit levée ou non." msdn.microsoft.com/fr/us/library/ms173179.aspx

12 votes

Quel est l'intérêt de la ligne var temp = obj ;. Puisque c'est juste une référence au départ, à quoi bon en créer une autre ?

18 votes

@priehl Il permet à l'utilisateur de modifier obj sans que le système entier ne se bloque.

345voto

Umar Abbas Points 188

C'est plus simple que vous ne le pensez.

Selon Microsoft : Le site lock garantit qu'un thread n'entre pas dans une section critique du code alors qu'un autre thread se trouve dans la section critique. Si un autre thread tente d'entrer dans un code verrouillé, il attendra, bloqué, que l'objet soit libéré.

El lock appels par mots-clés Enter au début du bloc et Exit à la fin du bloc. lock Le mot clé gère en fait Monitor à l'arrière.

Par exemple :

private static readonly Object obj = new Object();

lock (obj)
{
    // critical section
}

Dans le code ci-dessus, le thread entre d'abord dans une section critique, puis il se verrouille. obj . Lorsqu'un autre thread essaie d'entrer, il essaie également de verrouiller obj qui est déjà verrouillé par le premier fil. Le deuxième fil devra attendre que le premier fil libère le verrou. obj . Lorsque le premier fil s'en va, un autre fil va verrouiller obj et va entrer dans la section critique.

15 votes

Devons-nous créer un objet fictif à verrouiller ou pouvons-nous verrouiller une variable existante dans le contexte ?

15 votes

@batmaci - Le verrouillage sur un objet fictif privé distinct vous donne la garantie que personne d'autre ne verrouille cet objet. Si vous verrouillez les données et que ces mêmes données sont visibles de l'extérieur, vous perdez cette garantie.

9 votes

Que se passe-t-il si plus d'un processus attend la libération du verrou ? Les processus en attente sont-ils mis en file d'attente de manière à ce qu'ils verrouillent la section critique dans l'ordre FIFO ?

55voto

ArsenMkrt Points 24447

Non, ils ne sont pas en attente, ils sont en train de dormir.

Une déclaration de verrouillage de la forme

lock (x) ... 

où x est une expression d'un type de référence, est précisément équivalent à

var temp = x;
System.Threading.Monitor.Enter(temp); 
try { ... } 
finally { System.Threading.Monitor.Exit(temp); }

Il suffit de savoir qu'ils sont en attente l'un de l'autre, et qu'un seul thread entrera dans le bloc de verrouillage, les autres attendront...

Monitor est entièrement écrit en .net, il est donc assez rapide, regardez aussi classe Moniteur con réflecteur pour plus de détails

8 votes

Notez que le code émis pour le lock a été légèrement modifié en C#4 : blogs.msdn.com/b/ericlippert/archive/2009/03/06/

0 votes

@ArsenMkrt, ils ne sont pas maintenus dans l'état "Blocked" "Queue". Je pense qu'il y a une certaine différence entre l'état "Sleep" et l'état "Blocked", n'est-ce pas ?

0 votes

Quelle différence voulez-vous dire @Mohanavel ?

36voto

Andrew Points 2941

Les verrous bloquent l'exécution du code contenu dans le bloc verrouillé par les autres threads. Les threads devront attendre que le thread à l'intérieur du bloc de verrouillage ait terminé et que le verrou soit libéré. Cela a un impact négatif sur les performances dans un environnement multithread. Si vous devez procéder ainsi, assurez-vous que le code contenu dans le bloc de verrouillage peut être traité très rapidement. Essayez d'éviter les activités coûteuses comme l'accès à une base de données, etc.

10voto

Mr47 Points 2091

La partie de l'instruction de verrouillage ne peut être exécutée que par un seul thread, de sorte que tous les autres threads attendront indéfiniment que le thread qui détient le verrouillage ait terminé. Cela peut conduire à une impasse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X