SyncLock – příkaz

Získá výhradní zámek pro blok příkazu před spuštěním bloku.

Syntax

SyncLock lockobject  
    [ block ]  
End SyncLock  

Součásti

lockobject
Povinná hodnota. Výraz, který se vyhodnocuje jako odkaz na objekt.

block
Nepovinný parametr. Blok příkazů, které mají být provedeny při získání zámku.

End SyncLock
Ukončí SyncLock blok.

Poznámky

SyncLockPříkaz zajistí, že více vláken nespustí blok příkazu současně. SyncLock zabrání každému vláknu v vstupu do bloku, dokud žádné jiné vlákno neprovádí.

Nejběžnějším použitím nástroje SyncLock je chránit data před aktualizací více než jedním vláknem současně. Pokud příkazy, které pracují s daty, musí přejít k dokončení bez přerušení, umístit je dovnitř SyncLock bloku.

Blok příkazu chráněný výhradním zámkem se někdy nazývá kritická sekce.

Pravidla

  • Větvení. Nemůžete vytvořit větev do SyncLock bloku z vnějšího bloku.

  • Zamkne hodnotu objektu. Hodnota lockobject nemůže být Nothing . Objekt zámku je nutné vytvořit před jeho použitím v SyncLock příkazu.

    Při provádění bloku nelze změnit hodnotu lockobject SyncLock . Mechanismus vyžaduje, aby objekt zámku zůstal beze změny.

  • V bloku nelze použít operátor await SyncLock .

Chování

  • Mechanismy. 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ý podproces dosáhne SyncLock příkazu, nezíská zámek, dokud první vlákno neprovede End SyncLock příkaz.

  • Chráněná data. Pokud lockobject je Shared Proměnná, exkluzivní zámek zabraňuje vláknu v jakékoli instanci třídy, aby vyspustila blok, SyncLock zatímco jakékoli jiné vlákno ji provádí. Tato ochrana chrání data, která jsou sdílena mezi všemi instancemi.

    Pokud lockobject je proměnná instance (ne Shared ), zámek zabraňuje vláknu běžícímu v aktuální instanci spouštět SyncLock blok ve stejnou dobu jako jiné vlákno ve stejné instanci. Tato ochrana chrání data udržovaná individuální instancí.

  • Získání a vydání. SyncLockBlok se chová jako Try...Finally konstrukce, ve které Try blok získá výhradní zámek lockobject , a Finally blok ho uvolní. Z tohoto důvodu SyncLock blok garantuje vydání zámku bez ohledu na to, jak tento blok ukončujete. To platí i v případě neošetřené výjimky.

  • Volání rozhraní. SyncLockBlok získá a uvolní výhradní zámek voláním Enter Exit metod a Monitor třídy v System.Threading oboru názvů.

Postupy programování

lockobjectVýraz by měl vždy vyhodnocovat objekt, který patří exkluzivně do vaší třídy. Měli byste deklarovat Private objektovou proměnnou pro ochranu dat patřících k aktuální instanci nebo Private Shared proměnné objektu pro ochranu dat společných pro všechny instance.

Klíčové slovo byste neměli používat Me k poskytnutí objektu zámku pro data instance. Pokud má externí kód pro vaši třídu odkaz na instanci vaší třídy, může použít tento odkaz jako objekt zámku pro SyncLock blok zcela odlišný od vašeho ze své ochrany a chránit tak jiná data. Tímto způsobem může vaše třída a druhá třída vzájemně blokovat spouštění jejich nesouvisejících SyncLock bloků. Podobně zamykání na řetězci může být problematické, protože jakýkoliv jiný kód v procesu používající stejný řetězec bude sdílet stejný zámek.

Tuto metodu byste neměli používat ani Me.GetType k poskytnutí objektu zámku pro sdílená data. Je to proto GetType , že vždy vrátí stejný Type objekt pro daný název třídy. Externí kód by mohl zavolat GetType na vaši třídu a získat stejný objekt zámku, který používáte. To by vedlo ke vzájemnému blokování obou 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ím použitém elementu tohoto pole v proměnné. addAnotherMessageProcedura zvýší poslední prvek a uloží novou zprávu. Tyto dvě operace jsou chráněny pomocí SyncLock End SyncLock příkazů a, protože po zvýšení posledního prvku se musí nová zpráva uložit předtím, než jakékoli jiné vlákno bude moci znovu zvýšit poslední prvek.

Pokud simpleMessageList Třída sdílela jeden seznam zpráv mezi všemi jeho instancemi, proměnné messagesList a by měly messagesLast být deklarovány jako Shared . V takovém případě messagesLock by měla být proměnná také Shared , takže by existoval jediný objekt zámku, který používá každá instance.

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 . Pokud SyncLock je k dispozici příkaz, blok příkazu je nepostradatelným oddílem a balance nikdy se nestane záporným číslem. Můžete komentovat SyncLock příkazy a a podívat se, End SyncLock Jak SyncLock klíčové slovo opustí.

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é