SyncLock — Instrukcja

Uzyskuje wyłączną blokadę bloku instrukcji przed wykonaniem bloku.

Składnia

SyncLock lockobject  
    [ block ]  
End SyncLock  

generatora

lockobject
Wymagany. 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ć SyncLock bloku spoza bloku.

  • Zablokuj wartość obiektu. Wartość nie może być Nothingwartością lockobject . Przed użyciem go w instrukcji SyncLock należy utworzyć obiekt lock.

    Nie można zmienić wartości lockobject podczas wykonywania SyncLock bloku. Mechanizm wymaga, aby obiekt blokady pozostał niezmieniony.

  • Nie można użyć operatora Await w SyncLock bloku.

Zachowanie

  • Mechanizm. Gdy wątek osiągnie SyncLock instrukcję, oblicza lockobject wyraż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 instrukcji End SyncLock .

  • Chronione dane. Jeśli lockobject jest zmienną Shared , blokada wyłączna uniemożliwia wątkowi w dowolnym wystąpieniu klasy wykonywanie SyncLock bloku, podczas gdy jakikolwiek inny wątek go wykonuje. Chroni to dane, które są współużytkowane przez wszystkie wystąpienia.

    Jeśli lockobject jest zmienną wystąpienia (nie Shared), blokada uniemożliwia wątkowi uruchomionemu w bieżącym wystąpieniu wykonywanie SyncLock bloku 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 SyncLock zachowuje się jak Try...Finally konstrukcja, w której Try blok uzyskuje wyłączną blokadę lockobject i Finally blok go zwalnia. W związku z tym SyncLock blok 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 SyncLock uzyskuje i zwalnia blokadę wyłączną przez wywołanie Enter metod Monitor i Exit klasy 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.

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

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 .

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

Komentarze

Zobacz też