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?
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é leExit
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 appelleEnter
plusieurs fois sans qu'il se bloque; Cependant, un nombre égal d'appelsExit
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.
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.
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.
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.
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.
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.
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.
verrouiller est réellement caché Moniteur classe.