2010-09-10 14 views
14

Possible en double:
Re-entrant locks in C#récursive/verrouillage imbriqué en C# avec l'instruction lock

Je l'ai regardé ici sur StackOverflow et MSDN, et ne peut pas croire que je ne pourrais pas Je ne trouve pas cette question sur les internets.

Disons que j'ai une classe avec un membre privé auquel je veux accéder dans plusieurs méthodes publiques. Ces méthodes publiques seront appelées par des threads différents, d'où le besoin de synchronisation.

public class MyClass 
{ 
    private Object SomeSharedData = new Object(); 

    public void MethodA() 
    { 
     lock(SomeSharedData) { 
      // do something 
      MethodB(); 
     } 
    } 

    public void MethodB() 
    { 
     lock(SomeSharedData) { 
      // do something 
     } 
    } 
} 

Notez que METHODA et MethodB peuvent être appelés par les utilisateurs de cette classe, mais METHODA appelle aussi MethodB, qui se traduit par une condition de verrouillage imbriqué.

Est-ce garanti pour être sûr? En d'autres termes, .NET gère-t-il cela par référence en comptant le verrou, de sorte que lorsque je sors de ces méthodes, le verrou est décrémenté? Ou est-ce que .NET effectue de la magie derrière la scène, en ignorant simplement tous les verrous suivants sur l'objet provenant du même thread?

+3

verrouillage Pour votre information est juste du sucre syntaxique sur Monitor.Enter Monitor.Exit –

+0

@Sergey merci, je pense que je fait J'ai lu ça une fois dans mon livre C# mais je n'ai pas pu le trouver. – Dave

+0

@ M4N ack, je n'ai pas vérifié "re-entrant" :) – Dave

Répondre

16

Oui, les verrous basés sur Monitor dans .NET sont récursifs et comptés.

De la documentation pour Monitor.Enter:

Il est légal pour le même fil à Invoke Entrez plus d'une fois sans elle de blocage; Toutefois, un nombre égal d'appels de sortie doit être appelé avant que les autres threads en attente sur l'objet ne se débloquent.

Que ce soit une bonne chose ou non pour le débat ...

+0

Le lien "up for debate" va à la documentation Monitor.Enter. Pouvez-vous éditer votre réponse et fournir le lien que vous avez prévu? –

+0

ok, cela a du sens. Maintenant, je devrais juste tester cela avec une petite application, mais je suppose que si une exception est levée et non gérée dans l'instruction lock() {}, que le compte ref est toujours décrémenté? – Dave

+0

@Dave il est décrémenté. – eglasius

4

Oui, Monitor récursion de soutien, mais vous devez être conscient parce que ce comportement diffère d'une primitive de synchronisation à l'autre.

Par exemple, ReaderWriterLockSlim par défaut ne prend pas en charge la récursivité et cet extrait de code throws Exception:

public class MyClass 
{ 
    ReaderWriterLockSlim rw = new ReaderWriterLockSlim(); 
    //You should explicitly stated that you want to use recursion 
    ReaderWriterLockSlim rwWithRecursion = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion); 

    public void MethodA() 
    { 
     try { 
      rw.EnterReadLock(); 
      // do something 
      MethodB(); 
     } 
     finally { 
      rw.ExitReadLock(); 
     } 
    } 

    public void MethodB() 
    { 
     try { 
      rw.EnterReadLock(); //throws LockRecursionException 
     } 
     finally { 
      rw.ExitReadLock(); 
     } 
    } 
} 
+0

merci, je garderai cela à l'esprit.Je n'ai pas trouvé un besoin pour ReaderWriterLockSlim encore, mais j'ai lu à ce sujet avant et il pourrait être utile un jour, donc j'espère que je me souviendrai de votre conseil.:) – Dave