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ýt Nothing. Objekt lock musíte vytvořit před použitím v SyncLock 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áhne SyncLock 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 (ne Shared), zámek zabrání vláknu spuštěného v aktuální instanci spustit SyncLock 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á jako Try...Finally konstrukce, ve které Try blok získá výhradní zámek lockobject a blok ho Finally uvolní. Z tohoto důvodu SyncLock 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ím Enter a Exit metodami Monitor 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 Sharedpromě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

Komentáře

Viz také