Verrouillage du rentrant en C #

Le code suivant provoquera-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 } } } 

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

lock(object) {...} est un raccourci pour utiliser la classe Monitor . Comme le fait remarquer Marc , Monitor permet la ré-appartenance , de sorte que les tentatives répétées de verrouiller un object sur lequel le thread actuel a déjà un verrou fonctionnent correctement.

Si vous commencez à verrouiller différents objects, vous devez faire attention. Portez une attention particulière à:

  • Toujours acquérir des verrous sur un nombre donné d’objects dans la même séquence.
  • Relâchez toujours les verrous dans l’ordre inverse de leur acquisition.

Si vous enfreignez l’une 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/

Verrouillez aussi peu d’objects que possible. Pensez à utiliser des serrures à gros grains si possible. L’idée étant que si vous pouvez écrire votre code de telle sorte qu’il existe un graphe d’object et que vous puissiez acquérir des verrous à la racine de ce graphe d’object, faites-le. Cela signifie que vous avez un verrou sur cet object racine et que vous n’avez donc pas à vous soucier de la séquence dans laquelle vous acquérez / libérez des 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.)

Eh bien, Monitor permet la ré-appartenance, donc vous ne pouvez pas vous bloquer … alors non: ça ne devrait pas faire

Si un thread contient déjà un verrou, il ne se bloquera pas. Le framework .Net le garantit. Vous devez seulement vous assurer que deux threads ne tentent pas d’obtenir les deux mêmes verrous hors séquence par des chemins de code quelconques.

Le même thread peut acquérir le même verrou plusieurs fois, mais vous devez vous assurer de libérer le verrou autant de fois que vous l’avez acquis. Bien sûr, tant que vous utilisez le mot-clé “lock” pour cela, cela se fait automatiquement.

Non, ce code n’aura pas de verrous morts. Si vous voulez vraiment créer un blocage, le plus simple nécessite au moins 2 ressources. Considérez le scénario chien et 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 requirejs au minimum pour créer une impasse lorsqu’ils bloquent respectivement leurs os et cherchent d’autres os aussi.

.. et ainsi de suite n chiens et os et causer des impasses plus sophistiquées.