SyncLock-instructie
Hiermee verkrijgt u een exclusieve vergrendeling voor een instructieblok voordat u het blok uitvoert.
Syntaxis
SyncLock lockobject
[ block ]
End SyncLock
generator
lockobject
Vereist. Expressie die resulteert in een objectverwijzing.
block
Optioneel. Blok met instructies die moeten worden uitgevoerd wanneer de vergrendeling wordt verkregen.
End SyncLock
Hiermee wordt een SyncLock
blok beëindigd.
Opmerkingen
De SyncLock
instructie zorgt ervoor dat meerdere threads het instructieblok niet tegelijkertijd uitvoeren. SyncLock
voorkomt dat elke thread het blok invoert totdat er geen andere thread wordt uitgevoerd.
Het meest voorkomende gebruik van SyncLock
is om gegevens te beschermen tegen het tegelijkertijd bijwerken van meer dan één thread. Als de instructies waarmee de gegevens worden bewerkt, zonder onderbreking moeten worden voltooid, plaatst u deze in een SyncLock
blok.
Een instructieblok dat wordt beveiligd door een exclusieve vergrendeling, wordt ook wel een kritieke sectie genoemd.
Regels
Vertakking. U kunt niet vertakken naar een
SyncLock
blok van buiten het blok.Objectwaarde vergrendelen. De waarde van
lockobject
kan niet zijnNothing
. U moet het vergrendelingsobject maken voordat u het in eenSyncLock
instructie gebruikt.U kunt de waarde van het uitvoeren van
lockobject
eenSyncLock
blok niet wijzigen. Het mechanisme vereist dat het vergrendelingsobject ongewijzigd blijft.U kunt de operator Await niet in een
SyncLock
blok gebruiken.
Gedrag
Mechanisme. Wanneer een thread de
SyncLock
instructie bereikt, wordt de expressie geëvalueerd en wordt delockobject
uitvoering onderbroken totdat er een exclusieve vergrendeling wordt verkregen voor het object dat door de expressie wordt geretourneerd. Wanneer een andere thread deSyncLock
instructie bereikt, krijgt deze pas een vergrendeling als de eerste thread deEnd SyncLock
instructie uitvoert.Beveiligde gegevens. Als
lockobject
dit eenShared
variabele is, voorkomt de exclusieve vergrendeling dat een thread in een exemplaar van de klasse hetSyncLock
blok uitvoert terwijl een andere thread deze uitvoert. Hiermee worden gegevens beveiligd die worden gedeeld tussen alle exemplaren.Als
lockobject
dit een exemplaarvariabele is (nietShared
), voorkomt de vergrendeling dat een thread die wordt uitgevoerd in het huidige exemplaar hetSyncLock
blok tegelijkertijd uitvoert als een andere thread in hetzelfde exemplaar. Hiermee worden gegevens beschermd die worden onderhouden door het afzonderlijke exemplaar.Overname en release. Een
SyncLock
blok gedraagt zich als eenTry...Finally
constructie waarin hetTry
blok een exclusieve vergrendeling verwerftlockobject
en hetFinally
blok het vrijgeeft. Hierdoor garandeert het blok deSyncLock
release van de vergrendeling, ongeacht hoe u het blok afsluit. Dit geldt zelfs in het geval van een onverwerkte uitzondering.Framework-aanroepen. Het
SyncLock
blok verkrijgt en publiceert de exclusieve vergrendeling door deEnter
enExit
methoden van deMonitor
klasse in de System.Threading naamruimte aan te roepen.
Programmeerprocedures
De lockobject
expressie moet altijd evalueren naar een object dat exclusief bij uw klasse hoort. U moet een Private
objectvariabele declareren om gegevens te beveiligen die behoren tot het huidige exemplaar of een Private Shared
objectvariabele om gegevens te beveiligen die voor alle exemplaren gebruikelijk zijn.
Gebruik het Me
trefwoord niet om een vergrendelingsobject voor exemplaargegevens op te geven. Als code buiten uw klasse een verwijzing heeft naar een exemplaar van uw klasse, kan deze verwijzing worden gebruikt als een vergrendelingsobject voor een SyncLock
blok dat volledig verschilt van die van u, waardoor verschillende gegevens worden beveiligd. Op deze manier kunnen uw klas en de andere klasse elkaar blokkeren om hun niet-gerelateerde SyncLock
blokken uit te voeren. Het vergrendelen van een tekenreeks kan ook problematisch zijn, omdat elke andere code in het proces die dezelfde tekenreeks gebruikt, dezelfde vergrendeling deelt.
U moet ook niet de Me.GetType
methode gebruiken om een vergrendelingsobject voor gedeelde gegevens op te geven. Dit komt doordat GetType
altijd hetzelfde Type
object wordt geretourneerd voor een bepaalde klassenaam. Externe code kan uw klasse aanroepen GetType
en hetzelfde vergrendelingsobject verkrijgen dat u gebruikt. Dit zou ertoe leiden dat de twee klassen elkaar van hun SyncLock
blokken blokkeren.
Voorbeelden
Beschrijving
In het volgende voorbeeld ziet u een klasse die een eenvoudige lijst met berichten onderhoudt. Deze bevat de berichten in een matrix en het laatst gebruikte element van die matrix in een variabele. Met de addAnotherMessage
procedure wordt het laatste element verhoogd en wordt het nieuwe bericht opgeslagen. Deze twee bewerkingen worden beveiligd door de SyncLock
en End SyncLock
instructies, omdat nadat het laatste element is verhoogd, het nieuwe bericht moet worden opgeslagen voordat een andere thread het laatste element opnieuw kan verhogen.
Als de simpleMessageList
klasse één lijst met berichten over alle exemplaren heeft gedeeld, worden de variabelen messagesList
messagesLast
gedeclareerd als Shared
. In dit geval moet de variabele messagesLock
ook zijn Shared
, zodat er één vergrendelingsobject wordt gebruikt door elk exemplaar.
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
Beschrijving
In het volgende voorbeeld worden threads en SyncLock
. Zolang de SyncLock
instructie aanwezig is, is het instructieblok een kritieke sectie en balance
wordt het nooit een negatief getal. U kunt opmerkingen toevoegen aan de SyncLock
en End SyncLock
instructies om het effect van het weglaten van het SyncLock
trefwoord te zien.
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