SyncLock-Anweisung
Ruft vor dem Ausführen des Anweisungsblocks eine exklusive Sperre für den Block ab.
SyncLock lockobject
[ block ]
End SyncLock
Teile
lockobject
Erforderlich. Ausdruck, der einen Objektverweis ergibt.block
Dies ist 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 mehrere Threads den Anweisungsblock nicht gleichzeitig ausführen. SyncLock verhindert, dass jeder Thread in den Block eintritt, bis dieser von keinem anderen Thread 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.
Sie können den Rechnen Sie-Operator in einem SyncLock-Block nicht verwenden.
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.
Beispiele
Description
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.
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.
Code
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
If messagesLast < messagesList.Length Then
messagesList(messagesLast) = newMessage
End If
End SyncLock
End Sub
End Class
Description
Im folgenden Beispiel werden Threads und SyncLock verwendet. Solange die SyncLock-Anweisung vorhanden ist, stellt der Anweisungsblock einen kritischen Abschnitt dar, und balance wird nie eine negative Zahl. Sie können die Anweisungen SyncLock und End SyncLock auskommentieren, um die Folgen der Auslassung des SyncLock-Schlüsselworts zu erkennen.
Code
Imports System.Threading
Module Module1
Class Account
Dim thisLock As New Object
Dim balance As Integer
Dim r As New Random()
Public Sub New(ByVal initial As Integer)
balance = initial
End Sub
Public Function Withdraw(ByVal amount As Integer) As Integer
' This condition will never be true unless the SyncLock statement
' is commented out:
If balance < 0 Then
Throw New Exception("Negative Balance")
End If
' Comment out the SyncLock and End SyncLock lines to see
' the effect of leaving out the SyncLock keyword.
SyncLock thisLock
If balance >= amount Then
Console.WriteLine("Balance before Withdrawal : " & balance)
Console.WriteLine("Amount to Withdraw : -" & amount)
balance = balance - amount
Console.WriteLine("Balance after Withdrawal : " & balance)
Return amount
Else
' Transaction rejected.
Return 0
End If
End SyncLock
End Function
Public Sub DoTransactions()
For i As Integer = 0 To 99
Withdraw(r.Next(1, 100))
Next
End Sub
End Class
Sub Main()
Dim threads(10) As Thread
Dim acc As New Account(1000)
For i As Integer = 0 To 9
Dim t As New Thread(New ThreadStart(AddressOf acc.DoTransactions))
threads(i) = t
Next
For i As Integer = 0 To 9
threads(i).Start()
Next
End Sub
End Module
Siehe auch
Referenz
Threadsynchronisierung (C# und Visual Basic)