web-dev-qa-db-fra.com

serrure à l'intérieur de la serrure

Je me demande si cette construction va provoquer une erreur:

lock(sync)
{
  // something
  lock(sync)
  {
    //something
    lock(sync)
    {
      //something
    }
  }
}

J'ai exécuté ce code, et cela semble correct, mais peut-être que dans certaines circonstances une erreur peut être générée?

63
reizals

lock est un wrapper pour Monitor.Enter et Monitor.Exit :

Le mot clé lock appelle Enter au début du bloc et Exit à la fin du bloc. D'après la documentation du premier:

D'après la documentation de Monitor.Enter :

Il est légal que le même thread appelle Enter plus d'une fois sans le bloquer; cependant, un nombre égal d'appels Exit doit être appelé avant que d'autres threads en attente sur l'objet ne se débloquent.

Étant donné que les appels à Enter et Exit sont associés, votre modèle de code a un comportement bien défini.

Notez cependant que lock n'est pas garanti d'être une construction sans exception:

Un ThreadInterruptedException est levé si Interrupt interrompt un thread qui attend d'entrer une instruction lock.

47
ta.speot.is

Pour expliquer pourquoi il s'agit d'un comportement bien défini et qui n'échouera jamais:

Mis à part: Cette réponse contient de meilleurs détails sur le fonctionnement réel des verrous

Le verrou se produit au niveau Thread, donc l'appeler une deuxième fois sur le même thread sera redondant. Je pense qu'il n'y aurait pas de pénalité de performance (bien que cela dépende de la façon dont les composants internes de .Net sont écrits, je ne peux donc pas garantir cela)

Plusieurs fois, vous auriez une fonction publique qui appelle une autre fonction publique de votre classe, qui ont toutes deux besoin du verrou lorsqu'elles sont utilisées séparément. Si cela n'était pas autorisé, les éléments suivants échoueraient:

private Dictionary<string, int> database = new Dictionary<string, int>();
private object databaseLock = new object();
public void AddOrUpdate(string item)
{
    lock (databaseLock)
    {
        if (Exists(item))
            database.Add(item, 1);
        else
            ++database[item];
    }
}
public bool Exists(string item)
{
    lock (databaseLock)
    {
        //... Maybe some pre-processing of the key or item...
        return database.ContainsKey(item);
    }
}
16
Thymine

Selon MSDN (voir ici et ici ), ce comportement est bien défini et ne pose aucun problème.

0
Yahia