web-dev-qa-db-fra.com

Comment fonctionne le verrouillage exactement?

Je vois que pour utiliser des objets qui ne sont pas thread-safe, nous enveloppons le code avec un verrou comme celui-ci:

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 en file d'attente? Si oui combien de temps vont-ils attendre?

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

465
NLV

L'instruction 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:

Utilisez Enter pour acquérir le moniteur sur l'objet transmis en tant que paramètre. Si un autre thread a exécuté Enter sur l'objet mais n'a pas encore exécuté le Exit correspondant, le thread en cours sera bloqué jusqu'à ce que l'autre thread libère l'objet. Il est légal qu'un même thread appelle Enter plusieurs fois sans qu'il se bloque; Cependant, un nombre égal d'appels Exit doit être appelé avant que d'autres threads en attente sur l'objet ne se débloquent.

La méthode Monitor.Enter attendra indéfiniment; il pas expire.

411
Steven

C'est plus simple que vous ne le pensez.

Selon Microsoft : le mot clé lock garantit qu'un thread ne pénètre pas dans une section de code critique tandis qu'un autre est dans la section critique. Si un autre thread tente d'entrer un code verrouillé, il attendra, bloquera, jusqu'à ce que l'objet soit libéré.

Le mot clé lock appelle Enter au début du bloc et Exit à la fin du bloc. Le mot clé lock gère en réalité Monitor la classe à 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 verrouille obj. Lorsqu'un autre thread tente d'entrer, il essaiera également de verrouiller obj, qui est déjà verrouillé par le premier thread. Je vais devoir attendre que le premier thread libère obj. Lorsque le premier thread quitte, un autre thread bloquera obj et entrera dans la section critique.

243
Umar Abbas

Non, ils ne sont pas en file d'attente, ils dorment

Une déclaration de verrouillage du formulaire

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); }

Vous avez juste besoin de savoir qu’ils s’attendent, et qu’un seul thread entrera pour verrouiller le blocage, les autres attendront ...

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

43
Arsen Mkrtchyan

Les verrous empêcheront les autres threads d’exécuter le code contenu dans le verrou. Les threads devront attendre que le thread à l'intérieur du bloc de verrouillage soit terminé et que le verrou soit libéré. Cela a un impact négatif sur les performances dans un environnement multithread. Si vous avez besoin de le faire, assurez-vous que le code contenu dans le bloc de verrouillage peut être traité très rapidement. Vous devriez essayer d'éviter des activités coûteuses comme accéder à une base de données, etc.

26
Andrew

L'impact sur les performances dépend de la façon dont vous verrouillez. Vous pouvez trouver une bonne liste d’optimisations ici: http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/ =

En gros, vous devriez essayer de verrouiller le moins possible, car cela met votre code en attente en veille. Si vous avez des calculs lourds ou du code de longue durée (téléchargement de fichier, par exemple) dans une serrure, cela entraîne une perte de performances considérable.

10
Simon Woker

La partie dans l'instruction de verrouillage ne peut être exécutée que par un seul thread. Par conséquent, tous les autres threads attendront indéfiniment que le thread qui détient le verrou se termine. Cela peut entraîner une soi-disant impasse.

7
Mr47

L'instruction lock est traduite en appels aux méthodes Enter et Exit de Monitor .

L'instruction lock attend indéfiniment la libération de l'objet de verrouillage.

7
Paolo Tedesco

verrouiller est réellement caché Moniteur classe.

4
Euphoric