Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uzyskuje wyłączną blokadę bloku instrukcji przed wykonaniem bloku.
Składnia
SyncLock lockobject
[ block ]
End SyncLock
Części
lockobject
To jest wymagane. Wyrażenie, które oblicza odwołanie do obiektu.
block
Opcjonalny. Blok instrukcji, które mają być wykonywane po uzyskaniu blokady.
End SyncLock
SyncLock Przerywa blok.
Uwagi
Instrukcja SyncLock zapewnia, że wiele wątków nie wykonuje jednocześnie bloku instrukcji.
SyncLock uniemożliwia każdemu wątkowi wprowadzanie bloku do momentu, aż żaden inny wątek nie zostanie on wykonywany.
Najczęstszym zastosowaniem programu SyncLock jest ochrona danych przed aktualizowaniem przez więcej niż jeden wątek jednocześnie. Jeśli instrukcje, które manipulują danymi, muszą przejść do zakończenia bez przerwy, umieść je w SyncLock bloku.
Blok instrukcji chroniony przez blokadę wyłączną jest czasami nazywany sekcją krytyczną.
Reguły
Rozgałęzienia. Nie można rozgałęzić
SyncLockbloku spoza bloku.Zablokuj wartość obiektu. Wartość nie może być
Nothingwartościąlockobject. Przed użyciem go w instrukcjiSyncLocknależy utworzyć obiekt lock.Nie można zmienić wartości
lockobjectpodczas wykonywaniaSyncLockbloku. Mechanizm wymaga, aby obiekt blokady pozostał niezmieniony.Nie można użyć operatora Await w
SyncLockbloku.
Zachowanie
Mechanizm. Gdy wątek osiągnie
SyncLockinstrukcję, obliczalockobjectwyrażenie i zawiesza wykonywanie, dopóki nie uzyska wyłącznej blokady obiektu zwróconego przez wyrażenie. Gdy inny wątek osiągnie instrukcjęSyncLock, nie uzyskuje blokady, dopóki pierwszy wątek nie wykona instrukcjiEnd SyncLock.Chronione dane. Jeśli
lockobjectjest zmiennąShared, blokada wyłączna uniemożliwia wątkowi w dowolnym wystąpieniu klasy wykonywanieSyncLockbloku, podczas gdy jakikolwiek inny wątek go wykonuje. Chroni to dane, które są współużytkowane przez wszystkie wystąpienia.Jeśli
lockobjectjest zmienną wystąpienia (nieShared), blokada uniemożliwia wątkowi uruchomionemu w bieżącym wystąpieniu wykonywanieSyncLockbloku w tym samym czasie co inny wątek w tym samym wystąpieniu. Chroni to dane przechowywane przez pojedyncze wystąpienie.Pozyskiwanie i wydawanie. Blok
SyncLockzachowuje się jakTry...Finallykonstrukcja, w którejTryblok uzyskuje wyłączną blokadęlockobjectiFinallyblok go zwalnia. W związku z tymSyncLockblok gwarantuje zwolnienie blokady, bez względu na sposób zamykania bloku. Jest to prawdą nawet w przypadku nieobsługiwanego wyjątku.Wywołania struktury. Blok
SyncLockuzyskuje i zwalnia blokadę wyłączną przez wywołanieEntermetodMonitoriExitklasy w System.Threading przestrzeni nazw.
Praktyki programistyczne
Wyrażenie lockobject powinno zawsze oceniać obiekt należący wyłącznie do klasy. Należy zadeklarować zmienną Private obiektu w celu ochrony danych należących do bieżącego wystąpienia lub Private Shared zmiennej obiektu w celu ochrony danych wspólnych dla wszystkich wystąpień.
Nie należy używać słowa kluczowego Me do udostępniania obiektu blokady dla danych wystąpień. Jeśli kod zewnętrzny klasy zawiera odwołanie do wystąpienia klasy, może użyć tego odwołania jako obiektu blokady dla SyncLock bloku zupełnie innego niż twoje, chroniąc różne dane. W ten sposób klasa i druga klasa mogą blokować sobie wykonywanie niepowiązanych SyncLock bloków. Podobnie blokowanie ciągu może być problematyczne, ponieważ każdy inny kod w procesie przy użyciu tego samego ciągu będzie współużytkować tę samą blokadę.
Nie należy również używać Me.GetType metody w celu udostępnienia obiektu blokady dla udostępnionych danych. Jest to spowodowane tym, że GetType zawsze zwraca ten sam Type obiekt dla danej nazwy klasy. Kod zewnętrzny może wywołać GetType klasę i uzyskać ten sam obiekt blokady, którego używasz. Spowodowałoby to zablokowanie sobie dwóch klas z ich SyncLock bloków.
Przykłady
Opis
W poniższym przykładzie przedstawiono klasę, która utrzymuje prostą listę komunikatów. Przechowuje komunikaty w tablicy i ostatni używany element tej tablicy w zmiennej. Procedura addAnotherMessage zwiększa ostatni element i przechowuje nowy komunikat. Te dwie operacje są chronione przez SyncLock instrukcje i End SyncLock , ponieważ po dokonaniu przyrostu ostatniego elementu nowy komunikat musi być przechowywany, zanim jakikolwiek inny wątek będzie mógł ponownie zwiększać ostatni element.
simpleMessageList Jeśli klasa udostępniła jedną listę komunikatów między wszystkimi wystąpieniami, zmienne messagesList i messagesLast zostaną zadeklarowane jako Shared. W takim przypadku zmienna powinna również mieć Sharedwartość messagesLock , aby istniał pojedynczy obiekt blokady używany przez każde wystąpienie.
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
Opis
W poniższym przykładzie użyto wątków i SyncLock. Jeśli instrukcja SyncLock jest obecna, blok instrukcji jest sekcją krytyczną i balance nigdy nie staje się liczbą ujemną. Możesz skomentować instrukcje SyncLock i End SyncLock , aby zobaczyć efekt pomijania słowa kluczowego SyncLock .
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