Duplicata possible:
Verrous rentrants en C #
Si j'écris du code comme celui-ci:
class Program {
static void Main(string[] args) {
Foo();
Console.ReadLine();
}
static void Foo() {
lock(_lock) {
Console.WriteLine("Foo");
Bar();
}
}
static void Bar() {
lock(_lock) {
Console.WriteLine("Bar");
}
}
private static readonly object _lock = new object();
}
J'obtiens en sortie:
Foo
Bar
Je m'attendais à ce que cela se bloque, car Foo acquiert un verrou, puis attend que Bar acquière le verrou. Mais cela n'arrive pas.
Le mécanisme de verrouillage le permet-il simplement parce que le code est exécuté sur le même thread?
Pour le même thread, un verrou est toujours rentrant , donc le thread peut verrouiller un objet aussi souvent qu'il le souhaite.
Parce que vous n'avez qu'un seul fil ici.
lock
est un raccourci pour
bool lockWasTaken = false;
var temp = obj;
try {
Monitor.Enter(temp, ref lockWasTaken);
// your thread safe code
}
finally { if (lockWasTaken) Monitor.Exit(temp); }
Monitor.Enter acquérir le moniteur sur l'objet passé en paramètre. Si un autre thread a exécuté une entrée sur l'objet mais n'a pas encore exécuté la sortie correspondante, le thread actuel se bloquera jusqu'à ce que l'autre thread libère l'objet. Il est légal que le même thread invoque Enter plus d'une fois sans le bloquer ; cependant, un nombre égal d'appels de sortie doit être appelé avant que d'autres threads en attente sur l'objet ne se débloquent.
Un mot: serrure réentrante. Si un thread a déjà acquis un verrou, il n'attend pas s'il souhaite acquérir à nouveau le verrou. C'est très nécessaire sinon cela aurait pu transformer des fonctions récursives simples en cauchemar.!
L'instruction lock
est plus intelligente que cela, et elle est conçue pour empêcher cela. Le verrou est "possédé" par le thread une fois qu'il y est entré, donc chaque fois qu'il atteint une autre instruction lock
qui verrouille le même objet, il se rendra compte qu'il a déjà accès à ce verrou.