SyncLock – příkaz
Před spuštěním bloku příkazu získá výhradní zámek bloku příkazu.
Syntaxe
SyncLock lockobject
[ block ]
End SyncLock
Součástky
lockobject
Povinný: Výraz, který se vyhodnotí jako odkaz na objekt
block
Nepovinné. Blok příkazů, které se mají provést při získání zámku.
End SyncLock
Ukončí SyncLock
blok.
Poznámky
Příkaz SyncLock
zajistí, že více vláken nespustí blok příkazu současně. SyncLock
zabrání každému vláknu vstoupit do bloku, dokud ho nespouštějí žádné jiné vlákno.
Nejběžnějším použitím SyncLock
je ochrana dat před aktualizací více než jedním vláknem současně. Pokud příkazy, které manipulují s daty, musí být dokončeny bez přerušení, vložte je do SyncLock
bloku.
Blok příkazu chráněný výhradním zámkem se někdy označuje jako kritický oddíl.
Pravidla
Větvení. Z vnějšího
SyncLock
bloku nelze vytvořit větev do bloku.Zamknout hodnotu objektu. Hodnota
lockobject
nemůže býtNothing
. Objekt lock musíte vytvořit před použitím vSyncLock
příkazu.Hodnotu
lockobject
při prováděníSyncLock
bloku nelze změnit. Mechanismus vyžaduje, aby objekt zámku zůstal beze změny.Operátor Await nelze použít v
SyncLock
bloku.
Chování
Mechanismus. Když vlákno dosáhne
SyncLock
příkazu, vyhodnotílockobject
výraz a pozastaví provádění, dokud nezíská výhradní zámek objektu vráceného výrazem. Když jiné vlákno dosáhneSyncLock
příkazu, nezíská zámek, dokud první vlákno nespustíEnd SyncLock
příkaz.Chráněná data. Pokud
lockobject
je proměnnáShared
, výhradní zámek zabraňuje vláknu v jakékoli instanci třídy v prováděníSyncLock
bloku, zatímco jakékoli jiné vlákno ho spouští. Tím se chrání data sdílená mezi všemi instancemi.Pokud
lockobject
je proměnná instance (neShared
), zámek zabrání vláknu spuštěného v aktuální instanci spustitSyncLock
blok ve stejnou dobu jako jiné vlákno ve stejné instanci. Tím se chrání data spravovaná jednotlivými instancemi.Získání a vydání. Blok
SyncLock
se chová jakoTry...Finally
konstrukce, ve kteréTry
blok získá výhradní zámeklockobject
a blok hoFinally
uvolní. Z tohoto důvoduSyncLock
blok zaručuje uvolnění zámku bez ohledu na to, jak blok opustíte. To platí i v případě neošetřené výjimky.Volání architektury.
SyncLock
Blok získá a uvolní výhradní zámek volánímEnter
aExit
metodamiMonitor
třídy v System.Threading oboru názvů.
Programovací postupy
Výraz lockobject
by se měl vždy vyhodnotit na objekt, který patří výhradně do vaší třídy. Měli byste deklarovat proměnnou objektu Private
, která chrání data patřící do aktuální instance, nebo proměnnou objektu Private Shared
, která chrání data společná pro všechny instance.
Klíčové slovo byste neměli používat Me
k poskytnutí objektu zámku pro data instance. Pokud má kód externí pro vaši třídu odkaz na instanci vaší třídy, může tento odkaz použít jako objekt zámku pro SyncLock
blok úplně jiný než váš a chránit jiná data. Tímto způsobem by vaše třída a druhá třída mohly navzájem blokovat provádění jejich nesouvisejících SyncLock
bloků. Podobně může být uzamčení řetězce problematické, protože jakýkoli jiný kód v procesu, který používá stejný řetězec, bude sdílet stejný zámek.
Neměli byste také použít metodu Me.GetType
k poskytnutí objektu zámku pro sdílená data. Důvodem je to, že GetType
vždy vrátí stejný Type
objekt pro daný název třídy. Externí kód může volat GetType
třídu a získat stejný objekt zámku, který používáte. To by vedlo ke vzájemnému blokování dvou tříd z jejich SyncLock
bloků.
Příklady
Popis
Následující příklad ukazuje třídu, která udržuje jednoduchý seznam zpráv. Obsahuje zprávy v poli a poslední použitý prvek tohoto pole v proměnné. Procedura addAnotherMessage
zvýší poslední prvek a uloží novou zprávu. Tyto dvě operace jsou chráněny SyncLock
příkazy a End SyncLock
příkazy, protože po zvýšení posledního prvku musí být nová zpráva uložena dříve, než jakékoli jiné vlákno může zvýšit poslední prvek znovu.
simpleMessageList
Pokud třída sdílela jeden seznam zpráv mezi všemi svými instancemi, proměnné messagesList
a messagesLast
budou deklarovány jako Shared
. V tomto případě by měla být Shared
proměnná messagesLock
také , takže by byl jeden objekt zámku používaný každou instancí.
Kód
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
Popis
Následující příklad používá vlákna a SyncLock
. SyncLock
Dokud je příkaz k dispozici, blok příkazu je kritický oddíl a balance
nikdy se nestane záporným číslem. Komentáře a End SyncLock
příkazy můžete okomentovatSyncLock
, abyste viděli efekt vynechání klíčového SyncLock
slova.
Kód
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