133 votes

Verrous réentrants en C#

Le code suivant aboutira-t-il à une impasse en utilisant C# sur .NET ?

 class MyClass
 {
    private object lockObj = new object();

    public void Foo()
    {
        lock(lockObj)
        { 
             Bar();
        }
    }

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }

169voto

Neil Barnwell Points 20731

Non, tant que vous verrouillez le même objet. Le code récursif a déjà le verrou et peut donc continuer sans entrave.

lock(object) {...} est une abréviation pour l'utilisation de l'option Moniteur classe. En tant que Marc souligne , Monitor permet [réentrée](http://en.wikipedia.org/wiki/Reentrant(subroutine))_ Les tentatives répétées de verrouillage d'un objet sur lequel le thread en cours a déjà un verrou fonctionnera parfaitement.

Si vous commencez à bloquer sur différents les objets, c'est là qu'il faut être prudent. Faites particulièrement attention :

  • Toujours acquérir des verrous sur un nombre donné d'objets dans la même séquence.
  • Déverrouillez toujours les serrures dans le inverser selon la manière dont vous les acquérez.

Si vous enfreignez l'une ou l'autre de ces règles, vous êtes pratiquement assuré d'obtenir des problèmes de blocage. à un moment donné .

Voici une bonne page web décrivant la synchronisation des threads dans .NET : http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/

De même, verrouillez aussi peu d'objets à la fois que possible. Envisagez d'appliquer écluses à gros grains dans la mesure du possible. L'idée est que si vous pouvez écrire votre code de manière à ce qu'il y ait un graphe d'objets et que vous puissiez acquérir des verrous sur la racine de ce graphe d'objets, faites-le. Cela signifie que vous disposez d'un seul verrou sur cet objet racine et que vous n'avez donc pas à vous préoccuper de l'ordre dans lequel vous acquérez/libérez les verrous.

(Par ailleurs, votre exemple n'est pas techniquement récursif. Pour qu'il soit récursif, Bar() devrait s'appeler lui-même, généralement dans le cadre d'une itération).

22voto

Marc Gravell Points 482669

Bien, Monitor permet la réentrance, de sorte que vous ne pouvez pas vous bloquer vous-même... donc non : il ne devrait pas faire de

8voto

Jeffrey L Whitledge Points 27574

Si un thread détient déjà un verrou, il ne se bloquera pas lui-même. C'est ce que garantit le cadre .Net. Il suffit de s'assurer que deux threads n'essaient pas d'acquérir les deux mêmes verrous hors séquence par n'importe quel chemin de code.

Le même thread peut acquérir le même verrou plusieurs fois, mais vous devez vous assurer que vous libérez le verrou le même nombre de fois que vous l'avez acquis. Bien entendu, tant que vous utilisez le mot-clé "lock" pour accomplir cette tâche, cela se fait automatiquement.

5voto

Rishabh Jain Points 83

Non, ce code ne comportera pas de serrures dormantes. Si vous voulez vraiment créer des blocages, le plus simple est de disposer d'au moins deux ressources. Prenons le cas du chien et de l'os. 1. Un chien a le contrôle total d'un os et tout autre chien doit attendre. 2. 2 chiens avec 2 os sont le minimum requis pour créer une impasse lorsqu'ils verrouillent leurs os respectivement et cherchent l'os d'un autre chien.

et ainsi de suite n chiens et m os et provoquent des blocages plus sophistiqués.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X