web-dev-qa-db-fra.com

Verrous rentrants en C #

Le code suivant entraînera-t-il un blocage 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 
        }
    }       
 }
112
Guy

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

lock(object) {...} est un raccourci pour utiliser la classe Monitor . Comme Marc souligne , Monitor permet ré-entrée, donc des tentatives répétées de verrouiller un objet sur lequel le thread actuel a déjà un verrou fonctionnera très bien.

Si vous commencez à verrouiller des objets différents, c'est là que vous devez faire attention. Portez une attention particulière à:

  • Toujours acquérir des verrous sur un nombre donné d'objets dans la même séquence.
  • Déverrouillez toujours les verrous dans l'ordre inverse de la façon dont vous les avez acquis.

Si vous enfreignez l'une de ces règles, vous avez à peu près la garantie 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/

En outre, verrouillez le moins d'objets à la fois possible. Envisagez d'appliquer verrous à gros grains dans la mesure du possible. L'idée étant que si vous pouvez écrire votre code de sorte qu'il existe un graphe d'objet et que vous puissiez acquérir des verrous à la racine de ce graphe d'objet, faites-le. Cela signifie que vous avez un verrou sur cet objet racine et que vous n'avez donc pas à vous soucier autant de la séquence dans laquelle vous acquérez/libérez les verrous.

(Une autre remarque, votre exemple n'est pas techniquement récursif. Pour qu'il soit récursif, Bar() devrait s'appeler, généralement dans le cadre d'une itération.)

140
Neil Barnwell

Eh bien, Monitor permet la rentrée, donc vous ne pouvez pas vous bloquer vous-même ... donc non: cela ne devrait pas faire

19
Marc Gravell

Si un thread détient déjà un verrou, il ne se bloquera pas. Le framework .Net le garantit. Vous devez seulement vous assurer que deux threads n'essaient pas d'acquérir les deux mêmes verrous hors séquence par les chemins de code.

Le même thread peut acquérir le même verrou plusieurs fois, mais vous devez vous assurer de libérer le verrou le même nombre de fois que vous l'avez acquis. Bien sûr, tant que vous utilisez le mot clé "lock" pour cela, cela se produit automatiquement.

6
Jeffrey L Whitledge

Non, ce code n'aura pas de verrous morts. Si vous voulez vraiment créer une impasse, la plus simple nécessite au moins 2 ressources. Considérez le scénario du chien et des os. 1. Un chien a le contrôle total sur 1 os, donc tout autre chien doit attendre. 2. 2 chiens avec 2 os sont nécessaires pour créer une impasse lorsqu'ils verrouillent leurs os respectivement et cherchent d'autres os aussi.

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

5
Rishabh Jain