SyncLock utasítás
A blokk végrehajtása előtt kizárólagos zárolást szerez be egy utasításblokkhoz.
Syntax
SyncLock lockobject
[ block ]
End SyncLock
Részek
lockobject
Szükséges. Objektumhivatkozásként kiértékelt kifejezés.
block
Opcionális. A zárolás beszerzésekor végrehajtandó utasítások blokkja.
End SyncLock
Leállítja a blokkot SyncLock
.
Megjegyzések
Az SyncLock
utasítás biztosítja, hogy több szál ne hajtsa végre egyszerre az utasításblokkot. SyncLock
megakadályozza, hogy az egyes szálak mindaddig belépnek a blokkba, amíg más szál nem hajtja végre.
A leggyakoribb használat SyncLock
az adatok több szál általi egyidejű frissítésének védelme. Ha az adatokat kezelő utasításoknak megszakítás nélkül kell befejeződniük, helyezze őket egy SyncLock
blokkba.
A kizárólagos zárolással védett utasításblokkokat kritikus szakasznak is nevezik.
Szabályok
Elágazó. A blokkon kívülről nem ágazhat be blokkba
SyncLock
.Objektumérték zárolása. Az érték
lockobject
nem lehetNothing
. A zárolási objektumot az utasításbanSyncLock
való használat előtt létre kell hoznia.A blokk végrehajtása közben nem módosíthatja
lockobject
az értékeketSyncLock
. A mechanizmus megköveteli, hogy a zárolási objektum változatlan maradjon.Blokkban nem használhatja a Várakozás operátort
SyncLock
.
Működés
Mechanizmus. Amikor egy szál eléri az
SyncLock
utasítást, kiértékeli a kifejezést, és felfüggeszti alockobject
végrehajtást, amíg nem szerez kizárólagos zárolást a kifejezés által visszaadott objektumon. Amikor egy másik szál eléri azSyncLock
utasítást, nem szerez be zárolást, amíg az első szál nem hajtja végre az utasítástEnd SyncLock
.Védett adatok. Ha
lockobject
változóShared
, a kizárólagos zárolás megakadályozza, hogy az osztály bármely példányában egy szál végrehajtsa aSyncLock
blokkot, miközben bármely más szál végrehajtja azt. Ez védi az összes példány között megosztott adatokat.Ha
lockobject
egy példányváltozó (nemShared
), a zárolás megakadályozza, hogy az aktuális példányban futó szál a blokkot ugyanabban aSyncLock
példányban egy másik szállal egyidejűleg hajtsa végre. Ez védi az egyes példányok által kezelt adatokat.Beszerzés és kiadás. A
SyncLock
blokkok úgy viselkednek, mint egyTry...Finally
olyan szerkezet, amelyben aTry
blokk kizárólagos zárolástlockobject
szerez be, és aFinally
blokk felszabadítja azt. Emiatt aSyncLock
blokk garantálja a zárolás feloldását, függetlenül attól, hogy hogyan lép ki a blokkból. Ez még kezeletlen kivétel esetén is igaz.Keretrendszerhívások. A
SyncLock
blokk a névtérben lévő osztály és metódusok meghívásávalEnter
szerzi be ésExit
oldja fel aMonitor
kizárólagos zárolást System.Threading .
Programozási eljárások
A lockobject
kifejezésnek mindig olyan objektumra kell kiértékelnie, amely kizárólag az osztályhoz tartozik. Deklarálnia kell egy objektumváltozót Private
az aktuális példányhoz tartozó adatok védelméhez, vagy egy objektumváltozót Private Shared
az összes példányra jellemző adatok védelméhez.
A kulcsszóval nem Me
adhat meg zárolási objektumot a példányadatokhoz. Ha az osztályon kívüli kód hivatkozással rendelkezik az osztály egy példányára, akkor ezt a hivatkozást használhatja zárolási objektumként egy SyncLock
olyan blokkhoz, amely teljesen eltér az Önétől, és védi a különböző adatokat. Ily módon az osztály és a másik osztály megakadályozhatja egymást a nem kapcsolódó SyncLock
blokkok végrehajtásában. Hasonlóképpen a sztring zárolása is problémás lehet, mivel az ugyanazon sztringet használó folyamat bármely más kódja ugyanazt a zárolást fogja használni.
A metódust nem használhatja Me.GetType
a megosztott adatok zárolási objektumának megadására. Ennek az az oka, hogy GetType
mindig ugyanazt Type
az objektumot adja vissza egy adott osztálynévhez. A külső kód meghívhatja GetType
az osztályt, és beszerezheti a használt zárolási objektumot. Ez azt eredményezné, hogy a két osztály blokkolja egymást a blokkjaikból SyncLock
.
Példák
Leírás
Az alábbi példa egy olyan osztályt mutat be, amely egyszerű üzenetlistát tart fenn. Egy tömbben lévő üzeneteket és a tömb utolsó használt elemét tárolja egy változóban. Az addAnotherMessage
eljárás növeli az utolsó elemet, és tárolja az új üzenetet. Ezt a két műveletet az és az SyncLock
End SyncLock
utasítások védik, mivel az utolsó elem növekménye után az új üzenetet tárolni kell, mielőtt bármely más szál újra növektetheti az utolsó elemet.
Ha az simpleMessageList
osztály az összes példánya között megosztott egy üzenetlistát, a változók messagesList
és messagesLast
a deklarálva Shared
lesznek. Ebben az esetben a változónak messagesLock
is meg kell lennie Shared
, hogy minden példány egyetlen zárolási objektumot használjon.
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
Leírás
Az alábbi példa szálakat és SyncLock
. Amíg az SyncLock
utasítás jelen van, az utasításblokk kritikus szakasz, és balance
soha nem lesz negatív szám. Megjegyzéseket fűzhet a SyncLock
kulcsszavakhoz, így End SyncLock
láthatja a kulcsszó kihagyásának SyncLock
hatását.
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