2016-04-19 3 views
0

Ich habe ein Problem mit dem gemeinsamen Zugriff bei der Verwendung von Monitor.Enter und Monitor.Exit. Manchmal hängt mein Code auf der folgenden Monitor.Exit Anweisung:Monitor.Exit() manchmal hängt

public void EndInit() 
{ 
    Monitor.Enter(this.lockObj); 
    this.initCount--; 
    if (this.initCount == 0) { 
     this.IsInitializing = false; 
     this.IsInitialized = true; 
     this.OnInitialized(); 
    } 
    // sometimes, this Exit will never return ... 
    Monitor.Exit(this.lockObj); 
} 

Es gibt nur einen anderen Ort, wo mein lockObj verwendet wird:

public void BeginInit() 
{ 
    Monitor.Enter(this.lockObj); 
    this.initCount++; 
    this.IsInitializing = true; 
    this.IsInitialized = false; 
    Monitor.Exit(this.lockObj); 
} 

Und das ist, wie ich dieses Sync-Objekt deklarieren:

private readonly object lockObj = new object(); 

ich reißen meine Haare, um herauszufinden, aus, was es hier vor sich geht, aber ohne Erfolg. Ich würde erwarten, Monitor.Enter() zu blockieren, bis mein Sync-Objekt freigegeben wird, aber warum ist Monitor.Exit() blockiert? Ich kann keine Erklärung für dieses Verhalten in MSDN entweder finden.

Hinweis Ich kann dieses Verhalten nicht reproduzieren, es tritt eher zufällig auf (gut, ich weiß, dass "zufällig" nicht die richtige Formulierung ist).

Alle Ideen oder hilfreiche Hinweise werden sehr geschätzt!

Thorsten

+1

Wenn möglich, dass Sie die 'Monitor.Enter' /' Monitor.Exit' Kombination mit einem 'Schloss ersetzen könnte() {}' Block. Was würde passieren, wenn vor dem Aufruf 'Monitor.Exit' eine Ausnahme ausgelöst wird? – Dbuggy

Antwort

3

ich eine Antwort von meinem vorherigen Kommentar zu machen. Weil Sie ein try finally Konstrukt verwendet haben sollten, damit die Monitor.Exit korrekt aufgerufen wird, wenn eine Ausnahme in der OnInitialize() auftritt.

So würde der Code dann

public void EndInit() 
{ 
    Monitor.Enter(this.lockObj); 
    try 
    { 
     this.initCount--; 
     if (this.initCount == 0) { 
      this.IsInitializing = false; 
      this.IsInitialized = true; 
      this.OnInitialized(); 
     } 
    } 
    finally 
    { 
     Monitor.Exit(this.lockObj);  
    } 
} 

werden Gleiches gilt für die zweite Methode geht.

Es kann auch dann wie folgt geschrieben werden kann here finden von Joe Albahari geschrieben

public void EndInit() 
{ 
    lock(this.lockObj) 
    { 
     this.initCount--; 
     if (this.initCount == 0) { 
      this.IsInitializing = false; 
      this.IsInitialized = true; 
      this.OnInitialized(); 
     } 
    } 
} 

bearbeiten

Eine sehr gute Erklärung auf Threading. Es ist eine wohlverdiente Lektüre.

Edit 2 (auf Vollständigkeit)

auch wie Damien_The_Unbeliever erwähnt, gibt es eine overload.

Dies funktioniert nur für .NET 4 und höher. Der Code, der den Monitor wäre dann:

public void EndInit() 
{ 
    bool lockAcuired = false; 
    try 
    { 
     Monitor.Enter(this.lockObj, ref lockAquired); 
     this.initCount--; 
     if (this.initCount == 0) { 
      this.IsInitializing = false; 
      this.IsInitialized = true; 
      this.OnInitialized(); 
     } 
    } 
    finally 
    { 
     if(lockAquired) 
      Monitor.Exit(this.lockObj);  
    } 
} 
+2

Wenn Sie die 'lock' manuell implementieren, sollten Sie die Variante verwenden, die das zwei Argument [' Enter'] verwendet (https://msdn.microsoft.com/en-us/library/dd289498 (v = vs.110) .aspx) * eingeschlossen * innerhalb des 'try' Blocks. Es wurde von eingeführt.NET 4 (glaube ich), um den Randfall einer Ausnahme zu behandeln, die geworfen wird, nachdem "Enter" zurückkehrt und der "try" -Baustein startet (in diesem Fall wird 'Exit' in Ihrer aktuellen Variante nicht aufgerufen) –

+0

Während des Schreibens Diese Frage und tiefer in meinen eigenen (alten) Code eingravierend, fand ich gerade die gleiche (mögliche) Quelle für dieses Problem heraus: 'OnInitialized()' kann eine Ausnahme werfen, die zur Zeit unbehandelt (und sogar unerkannt) wird. Ich habe diesen Aufruf aus dem Synchronisierungsblock entfernt und "try"/"catch" hinzugefügt. Zukunft wird zeigen, wenn dies das Problem behebt. – ThorstenHa

+0

@Damien_The_Unbeliever Ich habe meine Antwort für die .NET4-Version aktualisiert. Danke, dass du darauf hingewiesen hast. – Dbuggy