SyncLock-Anweisung
Aktualisiert: November 2007
Ruft vor dem Ausführen des Anweisungsblocks eine exklusive Sperre für den Block ab.
SyncLock lockobject
[ block ]
End SyncLock
Bestandteile
lockobject
Erforderlich. Ausdruck, der einen Objektverweis ergibt.block
Optional. Block von Anweisungen, die auszuführen sind, wenn die Sperre erworben wird.End SyncLock
Beendet einen SyncLock-Block.
Hinweise
Die SyncLock-Anweisung stellt sicher, dass der Anweisungsblock nicht von mehreren Threads gleichzeitig ausgeführt wird. SyncLock hindert die einzelnen Threads solange daran, den Block zu aktivieren, bis er von keinem anderen Thread mehr ausgeführt wird.
In der Regel wird SyncLock dazu verwendet, Daten vor der Aktualisierung durch mehrere Threads gleichzeitig zu schützen. Wenn die Anweisungen, mit denen die Daten bearbeitet werden, ohne Unterbrechung ausgeführt werden sollen, fügen Sie sie in einen SyncLock-Block ein.
Ein durch eine exklusive Sperre geschützter Anweisungsblock wird gelegentlich als kritischer Abschnitt bezeichnet.
Regeln
Verzweigen. Eine Verzweigung in einen SyncLock-Block ist nicht von außerhalb des Blocks möglich.
Wert des Sperrobjekts. Der Wert von lockobject kann nicht Nothing sein. Sie müssen das Sperrobjekt erstellen, bevor Sie es in einer SyncLock-Anweisung verwenden.
Sie können den Wert von lockobject nicht ändern, während ein SyncLock-Block ausgeführt wird. Der Mechanismus verlangt, dass das Sperrobjekt unverändert bleibt.
Verhalten
Mechanismus. Wenn ein Thread die SyncLock-Anweisung erreicht, wird der lockobject-Ausdruck ausgewertet und die Ausführung des Threads unterbrochen, bis der Thread eine exklusive Sperre für das durch den Ausdruck zurückgegebene Objekt erwirbt. Wenn ein anderer Thread die SyncLock-Anweisung erreicht, erwirbt er erst dann eine Sperre, wenn vom ersten Thread die End SyncLock-Anweisung ausgeführt wird.
Geschützte Daten. Wenn es sich bei lockobject um eine Shared-Variable handelt, hindert die exklusive Sperre einen Thread in jeder Instanz der Klasse daran, den SyncLock-Block auszuführen, wenn dieser von einem anderen Thread ausgeführt wird. Damit werden Daten geschützt, die für alle Instanzen freigegeben sind.
Wenn es sich bei lockobject um eine Instanzvariable (nicht Shared) handelt, hindert die Sperre einen Thread, der in der aktuellen Instanz ausgeführt wird, daran, den SyncLock-Block zur gleichen Zeit wie ein anderer Thread derselben Instanz auszuführen. Dadurch werden von der einzelnen Instanz verwaltete Daten geschützt.
Erwerb und Freigabe. Ein SyncLock-Block verhält sich wie eine Try...Finally-Konstruktion, bei der der Try-Block eine exklusive Sperre für lockobject erwirbt, die schließlich vom Finally-Block wieder aufgehoben wird. Daher garantiert der SyncLock-Block die Aufhebung der Sperre, unabhängig davon, wie Sie den Block beenden. Dies gilt sogar im Fall einer nicht behandelten Ausnahme.
Framework-Aufrufe. Der SyncLock-Block erwirbt die exklusive Sperre und gibt sie frei, indem er die Enter-Methode und die Exit-Methode der Monitor-Klasse im System.Threading-Namespace aufruft.
Programmierempfehlungen
Der lockobject-Ausdruck sollte stets ein Objekt ergeben, das ausschließlich zu der von Ihnen erstellten Klasse gehört. Sie sollten eine Private-Objektvariable deklarieren, um Daten zu schützen, die zu der aktuellen Instanz gehören, oder eine Private Shared-Objektvariable, um Daten zu schützen, die allen Instanzen gemeinsam sind.
Sie sollten das Me-Schlüsselwort nicht zur Bereitstellung eines Sperrobjekts für Instanzdaten verwenden. Wenn Code außerhalb der von Ihnen erstellten Klasse einen Verweis auf eine Instanz dieser Klasse enthält, kann dieser Code den Verweis als Sperrobjekt für einen völlig anderen Block als den von Ihnen erstellten SyncLock-Block verwenden, sodass andere Daten geschützt werden. Auf diese Weise könnten die von Ihnen erstellte Klasse und die andere Klasse die Ausführung der nicht zusammenhängenden SyncLock-Blöcke gegenseitig verhindern. Ebenso kann die Sperre einer Zeichenfolge problematisch sein, da in dem Prozess jeder andere Code, der dieselbe Zeichenfolge verwendet, dieselbe Sperre anwendet.
Außerdem sollten Sie die Me.GetType-Methode nicht zur Bereitstellung eines Sperrobjekts für freigegebene Daten verwenden. Grund hierfür ist, dass GetType stets das gleiche Type-Objekt für einen angegebenen Klassennamen zurückgibt. Externer Code könnte GetType für die von Ihnen erstellte Klasse aufrufen und das gleiche Sperrobjekt erhalten, das Sie verwenden. Dies würde dazu führen, dass beide Klassen einander durch ihre SyncLock-Blöcke blockieren würden.
Beispiel
Im folgenden Beispiel wird eine Klasse gezeigt, die eine einfache Liste mit Meldungen verwaltet. Die Meldungen werden in einem Array abgelegt, und das zuletzt verwendete Element dieses Arrays wird in einer Variablen abgelegt. Die addAnotherMessage-Prozedur erhöht das letzte Element und speichert die neue Meldung. Diese beiden Operationen werden durch die SyncLock-Anweisung und die End SyncLock-Anweisung geschützt, denn sobald das letzte Element erhöht wurde, muss die neue Meldung gespeichert werden; erst danach kann das letzte Element von einem anderen Thread erneut erhöht werden.
Class simpleMessageList
Public messagesList() As String = New String(50) {}
Public messagesLast As Integer = -1
Private messagesLock As New Object
Public Sub addAnotherMessage(ByVal newMessage As String)
SyncLock messagesLock
messagesLast += 1
messagesList(messagesLast) = newMessage
End SyncLock
End Sub
End Class
Würde die simpleMessageList-Klasse in allen Instanzen nur eine gemeinsame Liste von Meldungen verwenden, würden die messagesList-Variable und die messagesLast-Variable als Shared deklariert werden. In diesem Fall sollte die messagesLock-Variable ebenfalls Shared sein, sodass von jeder Instanz ein einziges Sperrobjekt verwendet werden würde.