Wiedereintretende Sperren in C #

119

Wird der folgende Code zu einem Deadlock bei Verwendung von C # in .NET führen?

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

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

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }
Kerl
quelle
6
Könnten wir erwägen, den Titel dieser Frage zu ändern - vielleicht in etwas wie das kürzlich geschlossene Warum verursachen verschachtelte Sperren keinen Deadlock? So wie es aussieht, scheint der Titel fast so gestaltet zu sein, dass die Leute ihn nicht entdecken können.
Jeff Sternal
12
Eigentlich fand ich dies basierend auf dem Suchwort "Wiedereintritt" und es beantwortete meine Frage. Wenn es eine dumme Frage ist, ist das ein anderes Problem ...
emfurry
Ich stimme dem Kommentar von @JeffSternal zu. Bei dieser Frage wird davon ausgegangen, dass die Person, die nach der Frage sucht, bereits mit "Wiedereintritts" -Sperren vertraut ist. Eine andere doppelte Frage hatte meiner Meinung nach einen guten Titel dafür: stackoverflow.com/questions/3687505/…
Luis Perez

Antworten:

148

Nein, nicht solange Sie dasselbe Objekt sperren. Der rekursive Code hat effektiv bereits die Sperre und kann daher ungehindert fortgesetzt werden.

lock(object) {...}ist eine Abkürzung für die Verwendung der Monitor- Klasse. Wie Marc weist darauf hin , Monitorermöglicht Neueintritt , so versucht auf einem Objekt Sperre wiederholt , auf dem der aktuelle Thread bereits eine Sperre hat wird gut funktionieren.

Wenn Sie anfangen, verschiedene Objekte zu sperren , müssen Sie vorsichtig sein. Achten Sie besonders auf:

  • Erwerben Sie immer Sperren für eine bestimmte Anzahl von Objekten in derselben Reihenfolge.
  • Lösen Sie Sperren immer in umgekehrter Reihenfolge, wie Sie sie erwerben.

Wenn Sie gegen eine dieser Regeln verstoßen, werden Sie garantiert irgendwann Deadlock-Probleme bekommen .

Hier ist eine gute Webseite, die die Thread-Synchronisation in .NET beschreibt: http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/

Sperren Sie außerdem so wenige Objekte wie möglich gleichzeitig. Erwägen Sie, wenn möglich, grobkörnige Schlösser anzubringen. Die Idee ist, dass Sie dies tun können, wenn Sie Ihren Code so schreiben können, dass ein Objektdiagramm vorhanden ist und Sie Sperren für die Wurzel dieses Objektdiagramms erwerben können. Dies bedeutet, dass Sie eine Sperre für dieses Stammobjekt haben und sich daher nicht so sehr um die Reihenfolge kümmern müssen, in der Sie Sperren erwerben / freigeben.

(Ein weiterer Hinweis: Ihr Beispiel ist technisch nicht rekursiv. Damit es rekursiv ist, Bar()muss es sich selbst aufrufen, normalerweise als Teil einer Iteration.)

Neil Barnwell
quelle
1
Besonders in verschiedenen Sequenzen.
Marc Gravell
6
Re Rekursion; tatsächlich; zu Guys Gunsten ist der Begriff wiedereintrittsfähig
Marc Gravell
Vielen Dank für die Klarstellung der Terminologie - ich habe die Frage bearbeitet und korrigiert.
Guy
Diese Frage scheint ziemlich viel Aufmerksamkeit zu bekommen, daher habe ich meine Antwort mit ein paar anderen Notizen aktualisiert, die ich mir seit dem ersten Schreiben ausgedacht habe.
Neil Barnwell
Eigentlich denke ich nicht, dass die Reihenfolge, in der Sie Sperren freigeben, von Bedeutung ist. Die Reihenfolge, in der Sie sie auswählen, ist definitiv gültig, aber solange das Freigeben der Sperre von nichts abhängig ist (Sie können sie jederzeit freigeben), sollten Sie in Ordnung sein, solange Sie alle von Ihnen erworbenen Sperren freigeben.
Bobroxsox
20

Nun, Monitorerlaubt Wiedereintritt, so dass Sie sich nicht selbst blockieren können ... also nein: es sollte nicht tun

Marc Gravell
quelle
7

Wenn ein Thread bereits eine Sperre hält, blockiert er sich nicht. Das .Net-Framework stellt dies sicher. Sie müssen nur sicherstellen, dass zwei Threads nicht versuchen, dieselben zwei Sperren außerhalb der Reihenfolge durch beliebige Codepfade zu erhalten.

Derselbe Thread kann dieselbe Sperre mehrmals erwerben, Sie müssen jedoch sicherstellen, dass Sie die Sperre genauso oft freigeben, wie Sie sie erwerben. Solange Sie das Schlüsselwort "lock" verwenden, geschieht dies natürlich automatisch.

Jeffrey L Whitledge
quelle
Beachten Sie, dass dies für Monitore gilt, jedoch nicht unbedingt für andere Arten von Sperren.
Jon Skeet
(Ich möchte nicht implizieren, dass Sie das natürlich nicht wussten - nur, dass es eine wichtige Unterscheidung ist :)
Jon Skeet
Das ist ein guter Punkt. Eigentlich wollte ich "Sperre" in "Monitor" ändern, aber dann wurde ich abgelenkt. Und faul. Und das Verhalten gilt auch für Windows-Mutex-Kernal-Objekte, also dachte ich mir, nah genug!
Jeffrey L Whitledge
5

Nein, dieser Code hat keine toten Sperren. Wenn Sie wirklich am einfachsten einen Deadlock erstellen möchten, sind mindestens 2 Ressourcen erforderlich. Betrachten Sie den Hund und das Knochenszenario. 1. Ein Hund hat die volle Kontrolle über 1 Knochen, sodass jeder andere Hund warten muss. 2. Es sind mindestens 2 Hunde mit 2 Knochen erforderlich, um einen Deadlock zu erzeugen, wenn sie ihre Knochen sperren und auch andere Knochen suchen.

.. so weiter und so fort n Hunde und m Knochen und verursachen anspruchsvollere Deadlocks.

Rishabh Jain
quelle