SyncLock-instruktion
Hämtar ett exklusivt lås för ett instruktionsblock innan blocket körs.
Syntax
SyncLock lockobject
[ block ]
End SyncLock
Delar
lockobject
Obligatoriska. Uttryck som utvärderas till en objektreferens.
block
Valfritt. Block med instruktioner som ska köras när låset hämtas.
End SyncLock
Avslutar ett SyncLock
block.
Kommentarer
-instruktionen SyncLock
ser till att flera trådar inte kör instruktionsblocket samtidigt. SyncLock
förhindrar att varje tråd kommer in i blocket förrän ingen annan tråd kör den.
Den vanligaste användningen av SyncLock
är att skydda data från att uppdateras av mer än en tråd samtidigt. Om de instruktioner som manipulerar data måste slutföras utan avbrott placerar du dem i ett SyncLock
block.
Ett instruktionsblock som skyddas av ett exklusivt lås kallas ibland för ett kritiskt avsnitt.
Regler
Förgrening. Du kan inte förgrena dig till ett
SyncLock
block utanför blocket.Lås objektvärde. Värdet för
lockobject
får inte varaNothing
. Du måste skapa låsobjektet innan du använder det i enSyncLock
-instruktion.Du kan inte ändra värdet
lockobject
för när du kör ettSyncLock
block. Mekanismen kräver att låsobjektet förblir oförändrat.Du kan inte använda Await-operatorn i ett
SyncLock
block.
Funktionssätt
Mekanism. När en tråd når -instruktionen
SyncLock
utvärderar den uttrycket och pausar körningenlockobject
tills den hämtar ett exklusivt lås på objektet som returneras av uttrycket. När en annan tråd når -instruktionenSyncLock
hämtar den inte ett lås förrän den första tråden kör -instruktionenEnd SyncLock
.Skyddade data. Om
lockobject
är enShared
variabel förhindrar det exklusiva låset att en tråd i någon instans av klassen körSyncLock
blocket medan någon annan tråd kör den. Detta skyddar data som delas mellan alla instanser.Om
lockobject
är en instansvariabel (inteShared
) förhindrar låset att en tråd som körs i den aktuella instansenSyncLock
kör blocket samtidigt som en annan tråd i samma instans. Detta skyddar data som underhålls av den enskilda instansen.Förvärv och lansering. Ett
SyncLock
block beter sig som enTry...Finally
konstruktion därTry
blocket hämtar ett exklusivt lås pålockobject
ochFinally
blocket släpper det. På grund av dettaSyncLock
garanterar blocket att låset släpps, oavsett hur du avslutar blocket. Detta gäller även i händelse av ett ohanterat undantag.Framework-anrop. Blocket
SyncLock
hämtar och släpper det exklusiva låset genom att anropa klassmetodernaEnter
Monitor
ochExit
i System.Threading namnområdet.
Programmeringsmetoder
Uttrycket lockobject
bör alltid utvärderas till ett objekt som uteslutande tillhör din klass. Du bör deklarera en Private
objektvariabel för att skydda data som tillhör den aktuella instansen eller en Private Shared
objektvariabel för att skydda data som är gemensamma för alla instanser.
Du bör inte använda nyckelordet Me
för att ange ett låsobjekt för instansdata. Om kod som är extern för klassen har en referens till en instans av klassen kan den använda den referensen som ett låsobjekt för ett SyncLock
block som är helt annorlunda än ditt, vilket skyddar olika data. På så sätt kan din klass och den andra klassen blockera varandra från att köra sina orelaterade SyncLock
block. På samma sätt kan det vara problematiskt att låsa en sträng eftersom all annan kod i processen som använder samma sträng delar samma lås.
Du bör inte heller använda Me.GetType
metoden för att ange ett låsobjekt för delade data. Det beror på att GetType
alltid returnerar samma Type
objekt för ett visst klassnamn. Extern kod kan anropa GetType
din klass och hämta samma låsobjekt som du använder. Detta skulle resultera i att de två klasserna blockerar varandra från sina SyncLock
block.
Exempel
beskrivning
I följande exempel visas en klass som upprätthåller en enkel lista med meddelanden. Den innehåller meddelandena i en matris och det senast använda elementet i matrisen i en variabel. Proceduren addAnotherMessage
ökar det sista elementet och lagrar det nya meddelandet. Dessa två åtgärder skyddas av instruktionen SyncLock
och End SyncLock
eftersom när det sista elementet har ökats måste det nya meddelandet lagras innan någon annan tråd kan öka det sista elementet igen.
simpleMessageList
Om klassen delade en lista med meddelanden mellan alla sina instanser deklareras variablerna messagesList
och messagesLast
som Shared
. I det här fallet bör variabeln messagesLock
också vara Shared
, så att det skulle finnas ett enda låsobjekt som används av varje instans.
Kod
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
beskrivning
I följande exempel används trådar och SyncLock
. Så länge instruktionen SyncLock
finns är instruktionsblocket ett kritiskt avsnitt och balance
blir aldrig ett negativt tal. Du kan kommentera ut instruktionen SyncLock
och End SyncLock
för att se effekten av att utelämna nyckelordet SyncLock
.
Kod
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