SyncLock-Anweisung
Ruft eine exklusive Sperre für einen Anweisungsblock ab, bevor der Block ausgeführt wird.
Syntax
SyncLock lockobject
[ block ]
End SyncLock
Bestandteile
lockobject
Erforderlich. Ausdruck, der einen Objektverweis auswertet.
block
Optional. Block von Anweisungen, die ausgeführt werden sollen, wenn die Sperre abgerufen wird.
End SyncLock
beendet einen SyncLock
-Block.
Bemerkungen
Die SyncLock
-Anweisung stellt sicher, dass nicht mehrere Threads gleichzeitig den Anweisungsblock ausführen. SyncLock
sorgt dafür, dass ein Thread den Block erst dann startet, wenn ihn kein anderer Thread mehr ausführt.
SyncLock
wird am häufigsten verwendet, um zu verhindern, dass Daten von mehreren Threads gleichzeitig aktualisiert werden. Wenn die Anweisungen, die die Daten bearbeiten, ohne Unterbrechung abgeschlossen werden müssen, platzieren Sie sie in einen SyncLock
-Block.
Ein Anweisungsblock, der durch eine exklusive Sperre geschützt wird, wird manchmal als kritischer Abschnitt bezeichnet.
Regeln
Branchen. Eine Verzweigung in einen
SyncLock
-Block von außerhalb ist nicht möglich.Sperrobjekt-Wert. Der Wert von
lockobject
kann nichtNothing
sein. Sie müssen das Sperrobjekt erstellen, bevor Sie es in einerSyncLock
-Anweisung verwenden.Sie können den Wert von
lockobject
während der Ausführung einesSyncLock
-Blocks nicht ändern. Der Mechanismus setzt voraus, dass das Sperrobjekt nicht geändert wird.Sie können den Await-Operator nicht in einem
SyncLock
-Block verwenden.
Verhalten
Mechanismus. Wenn ein Thread die
SyncLock
-Anweisung erreicht, wertet er denlockobject
-Ausdruck aus und setzt die Ausführung aus, bis er eine exklusive Sperre für das Objekt abgerufen hat, das vom Ausdruck zurückgegeben wird. Wenn ein weiterer Thread dieSyncLock
-Anweisung erreicht, ruft er erst eine Sperre ab, wenn der erste Thread dieEnd SyncLock
-Anweisung ausführt.Geschützte Daten. Wenn
lockobject
eineShared
-Variable ist, verhindert die exklusive Sperre, dass ein Thread in einer Instanz der Klasse denSyncLock
-Block ausführt, während er von einem anderen Thread ausgeführt wird. So werden Daten geschützt, die von allen Instanzen gemeinsam genutzt werden.Wenn
lockobject
eine Instanzvariable ist (nichtShared
), verhindert die Sperre, dass ein Thread, der in der aktuellen Instanz ausgeführt wird, denSyncLock
-Block zur selben Zeit ausführt wie ein anderer Thread in derselben Instanz. So werden Daten geschützt, die von der einzelnen Instanz verwaltet werden.Abruf und Freigabe. Ein
SyncLock
-Block verhält sich wie eineTry...Finally
-Konstruktion, in der derTry
-Block eine exklusive Sperre fürlockobject
abruft und derFinally
-Block sie freigibt. Aus diesem Grund gewährleistet derSyncLock
-Block die Freigabe der Sperre, unabhängig davon, wie Sie den Block verlassen. Das gilt selbst im Falle eines Ausnahmefehlers.Framework-Aufrufe. Der
SyncLock
-Block ruft die exklusive Sperre ab und gibt sie wieder frei, indem er die MethodenEnter
undExit
der KlasseMonitor
im Namespace System.Threading aufruft.
Programmierverfahren
Der Ausdruck lockobject
sollte immer zu einem Objekt ausgewertet werden, das exklusiv zu Ihrer Klasse gehört. Sie sollten eine Private
-Objektvariable so deklarieren, dass die Daten, die zur aktuellen Instanz gehören, geschützt werden, und eine Private Shared
-Objektvariable so, dass die Daten, die von allen Instanzen genutzt werden, geschützt werden.
Sie sollten das Schlüsselwort Me
nicht dazu verwenden, ein Sperrobjekt für Instanzdaten bereitzustellen. Wenn Code außerhalb Ihrer Klasse auf eine Instanz Ihrer Klasse verweist, könnte er diesen Verweis als Sperrobjekt für einen SyncLock
-Block verwenden, der völlig von Ihrem abweicht, sodass unterschiedliche Daten geschützt werden. So könnte es dazu kommen, dass Ihre Klasse und die andere Klasse sich gegenseitig davon abhalten, die nicht zusammenhängenden SyncLock
-Blöcke auszuführen. Auch die Sperre für eine Zeichenfolge kann problematisch sein, da jeder andere Code im Prozess, der dieselbe Zeichenfolge verwendet, auch dieselbe Sperre verwendet.
Sie sollten die Me.GetType
-Methode auch nicht dazu verwenden, ein Sperrobjekt für freigegebene Daten bereitzustellen. Grund dafür ist, dass GetType
immer dasselbe Type
-Objekt für einen Klassennamen zurückgibt. Externer Code könnte GetType
in Ihrer Klasse aufrufen und dasselbe Sperrobjekt abrufen, das Sie gerade verwenden. Dies würde dazu führen, dass die zwei Klassen sich gegenseitig davon abhalten, ihre SyncLock
-Blöcke auszuführen.
Beispiele
BESCHREIBUNG
Das folgende Beispiel zeigt eine Klasse, die eine einfache Liste an Nachrichten verwaltet. Die Nachrichten sind in einem Array enthalten, und das zuletzt verwendete Element dieses Arrays ist in einer Variablen enthalten. Die addAnotherMessage
-Prozedur erhöht das letzte Element und speichert es in einer neuen Nachricht. Diese zwei Vorgänge werden durch die SyncLock
- und End SyncLock
-Anweisungen geschützt, da nach dem Erhöhen des letzten Elements die neue Nachricht gespeichert werden muss, bevor ein anderer Thread das letzte Element erneut erhöhen kann.
Falls die Klasse simpleMessageList
eine Liste an Nachrichten für alle Instanzen freigegeben hat, würden die Variablen messagesList
und messagesLast
als Shared
deklariert werden. In diesem Fall sollte die Variable messagesLock
ebenfalls Shared
sein, damit es ein einziges Sperrobjekt gibt, das von jeder Instanz verwendet wird.
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
BESCHREIBUNG
Das folgende Beispiel verwendet Threads und SyncLock
. Solange die SyncLock
-Anweisung vorhanden ist, ist der Anweisungsblock ein kritischer Abschnitt und balance
wird niemals eine negative Zahl. Sie können die SyncLock
- und End SyncLock
-Anweisungen auskommentieren, um zu testen, welche Auswirkung das Weglassen des Schlüsselworts SyncLock
hat.
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