2010-12-14 5 views
6

Wann sollten Sperren verwendet werden? Nur beim Ändern von Daten oder beim Zugriff darauf?Sperren nur beim Ändern der gesamten Methode

Sollte es eine Sperre um den gesamten Block geben oder ist es in Ordnung, sie nur der tatsächlichen Änderung hinzuzufügen? Mein Verständnis ist, dass es immer noch eine Race Condition geben könnte, in der ein Call es vielleicht nicht gefunden hat und es hinzufügt, während ein anderer Call gleich danach in die gleiche Situation geraten ist - aber ich bin mir nicht sicher. Sperren ist immer noch so verwirrend. Ich habe keine Probleme mit dem oben genannten ähnlichen Code, aber ich konnte bisher nur Glück haben. Jede Hilfe oben würde geschätzt werden, sowie jede gute Ressourcen für wie/wann Objekte zu sperren.

Antwort

8

Sie müssen auch beim Lesen sperren, oder Sie erhalten unzuverlässige Daten oder sogar eine Ausnahme, wenn eine gleichzeitige Änderung die Zieldatenstruktur physisch ändert.

In dem obigen Fall müssen Sie sicherstellen, dass mehrere Threads nicht versuchen, den Wert zur gleichen Zeit hinzuzufügen, so dass Sie mindestens eine Lesesperre benötigen, während Sie überprüfen, ob es bereits vorhanden ist. Andernfalls könnten mehrere Threads entscheiden, hinzuzufügen, finden Sie den Wert nicht vorhanden (da diese Prüfung nicht gesperrt ist), und dann alle versuchen, der Reihe nach hinzufügen (

) Sie könnten ein ReaderWriterLockSlim verwenden, wenn Sie viele haben liest und nur ein paar schreibt. In dem obigen Code würden Sie die Lesesperre erwerben, um die Überprüfung durchzuführen und auf eine Schreibsperre zu aktualisieren, sobald Sie entscheiden, dass Sie sie hinzufügen müssen. In den meisten Fällen wird nur eine Lesesperre benötigt (die es Ihren Leser-Threads ermöglicht, noch parallel zu laufen).

Es gibt eine Zusammenfassung der verfügbaren .Net 4-Sperrgrundelemente here. Auf jeden Fall sollten Sie dies verstehen, bevor Sie sich mit Multithread-Code beschäftigen. Die Auswahl des richtigen Sperrmechanismus kann einen enormen Leistungsunterschied bewirken.

Sie haben Recht, dass Sie bisher Glück gehabt haben - das ist ein häufiges Merkmal von Nebenläufigkeitsfehlern. Sie sind oft ohne gezielte Belastungstests schwer zu reproduzieren, was bedeutet, dass ein korrektes Design (und erschöpfende Tests natürlich) unerlässlich ist, um peinliche und verwirrende Produktionsfehler zu vermeiden.

+0

Großen Link für alle verfügbaren Verriegelungsmechanismen. Ich hatte nur von 'Schloss' gehört. – MyNameIsJob

+0

Viel Glück - wenn Sie dieses Zeug meistern können, werden Sie in einer kleinen Minderheit von Entwicklern sein, die auf eine Zunahme der Multicore-Entwicklung gut vorbereitet sind. –

1

Sperren Sie den gesamten Block, bevor Sie das Vorhandensein von name überprüfen. Andernfalls könnte ein anderer Thread theoretisch zwischen der Prüfung und Ihrem Code, der sie hinzufügt, hinzufügen.

Tatsächlich sperren nur wenn Sie den Add ausführen, wirklich überhaupt nichts. Das würde nur verhindern, dass ein anderer Thread etwas gleichzeitig hinzufügt. Aber da dieser andere Thread bereits entschieden hätte, dass er den Add ausführen würde, würde er es einfach versuchen, sobald die Sperre aufgehoben wurde.

+1

Ein anderer Prozess? Terminologie ist wichtig. –

+0

Wahre enuf. Korrigiert. –

1

Wenn eine Ressource nur über mehrere Threads auf zugegriffen werden kann, sind keine Sperren erforderlich.

Wenn auf eine Ressource von mehreren Threads zugegriffen werden kann und geändert werden kann, müssen alle Zugriffe/Änderungen synchronisiert werden. Wenn in Ihrem Beispiel GetValueFromSomeWhere eine lange Zeit für die Rückgabe benötigt, ist es möglich, dass ein zweiter Aufruf mit demselben Wert in name erfolgt, der Wert wurde jedoch nicht in Dictionary gespeichert.

0

ReaderWriterLock oder die schlanke Version, wenn Sie unter 4.0.

Sie erhalten die Lesesperre für die Lesevorgänge (ermöglichen gleichzeitige Lesevorgänge) und aktualisieren die Sperre auf die Schreibsperre, wenn etwas geschrieben werden soll (erlaubt nur einen Schreibvorgang zu der Zeit und blockiert alle Lesevorgänge bis) erledigt, sowie die gleichzeitige write-threads).

Stellen Sie sicher, Ihre Sperren lösen mit dem Muster Deadlocks zu vermeiden:

  void Write(object[] args) 
      { 


        this.ReaderWriterLock.AquireWriteLock(TimeOut.Infinite); 

        try 
        { 
         this.myData.Write(args); 

        } 
        catch(Exception ex) 
        { 

        } 
        finally 
        { 

         this.ReaderWriterLock.RelaseWriterLock(); 
        } 

      } 
Verwandte Themen