Dela via


SyncLock-instruktion

Hämtar ett exklusivt lås för ett instruktionsblock innan blocket körs.

Syntax

SyncLock lockobject  
    [ block ]  
End SyncLock  

Delar

lockobject
Obligatoriska. Uttryck som utvärderas till en objektreferens.

block
Valfritt. Block med instruktioner som ska köras när låset hämtas.

End SyncLock
Avslutar ett SyncLock block.

Kommentarer

-instruktionen SyncLock ser till att flera trådar inte kör instruktionsblocket samtidigt. SyncLock förhindrar att varje tråd kommer in i blocket förrän ingen annan tråd kör den.

Den vanligaste användningen av SyncLock är att skydda data från att uppdateras av mer än en tråd samtidigt. Om de instruktioner som manipulerar data måste slutföras utan avbrott placerar du dem i ett SyncLock block.

Ett instruktionsblock som skyddas av ett exklusivt lås kallas ibland för ett kritiskt avsnitt.

Regler

  • Förgrening. Du kan inte förgrena dig till ett SyncLock block utanför blocket.

  • Lås objektvärde. Värdet för lockobject får inte vara Nothing. Du måste skapa låsobjektet innan du använder det i en SyncLock -instruktion.

    Du kan inte ändra värdet lockobject för när du kör ett SyncLock block. Mekanismen kräver att låsobjektet förblir oförändrat.

  • Du kan inte använda Await-operatorn i ett SyncLock block.

Funktionssätt

  • Mekanism. När en tråd når -instruktionen SyncLock utvärderar den uttrycket och pausar körningen lockobject tills den hämtar ett exklusivt lås på objektet som returneras av uttrycket. När en annan tråd når -instruktionen SyncLock hämtar den inte ett lås förrän den första tråden kör -instruktionen End SyncLock .

  • Skyddade data. Om lockobject är en Shared variabel förhindrar det exklusiva låset att en tråd i någon instans av klassen kör SyncLock blocket medan någon annan tråd kör den. Detta skyddar data som delas mellan alla instanser.

    Om lockobject är en instansvariabel (inte Shared) förhindrar låset att en tråd som körs i den aktuella instansen SyncLock kör blocket samtidigt som en annan tråd i samma instans. Detta skyddar data som underhålls av den enskilda instansen.

  • Förvärv och lansering. Ett SyncLock block beter sig som en Try...Finally konstruktion där Try blocket hämtar ett exklusivt lås på lockobject och Finally blocket släpper det. På grund av detta SyncLock garanterar blocket att låset släpps, oavsett hur du avslutar blocket. Detta gäller även i händelse av ett ohanterat undantag.

  • Framework-anrop. Blocket SyncLock hämtar och släpper det exklusiva låset genom att anropa klassmetoderna EnterMonitor och Exit i System.Threading namnområdet.

Programmeringsmetoder

Uttrycket lockobject bör alltid utvärderas till ett objekt som uteslutande tillhör din klass. Du bör deklarera en Private objektvariabel för att skydda data som tillhör den aktuella instansen eller en Private Shared objektvariabel för att skydda data som är gemensamma för alla instanser.

Du bör inte använda nyckelordet Me för att ange ett låsobjekt för instansdata. Om kod som är extern för klassen har en referens till en instans av klassen kan den använda den referensen som ett låsobjekt för ett SyncLock block som är helt annorlunda än ditt, vilket skyddar olika data. På så sätt kan din klass och den andra klassen blockera varandra från att köra sina orelaterade SyncLock block. På samma sätt kan det vara problematiskt att låsa en sträng eftersom all annan kod i processen som använder samma sträng delar samma lås.

Du bör inte heller använda Me.GetType metoden för att ange ett låsobjekt för delade data. Det beror på att GetType alltid returnerar samma Type objekt för ett visst klassnamn. Extern kod kan anropa GetType din klass och hämta samma låsobjekt som du använder. Detta skulle resultera i att de två klasserna blockerar varandra från sina SyncLock block.

Exempel

beskrivning

I följande exempel visas en klass som upprätthåller en enkel lista med meddelanden. Den innehåller meddelandena i en matris och det senast använda elementet i matrisen i en variabel. Proceduren addAnotherMessage ökar det sista elementet och lagrar det nya meddelandet. Dessa två åtgärder skyddas av instruktionen SyncLock och End SyncLock eftersom när det sista elementet har ökats måste det nya meddelandet lagras innan någon annan tråd kan öka det sista elementet igen.

simpleMessageList Om klassen delade en lista med meddelanden mellan alla sina instanser deklareras variablerna messagesList och messagesLast som Shared. I det här fallet bör variabeln messagesLock också vara Shared, så att det skulle finnas ett enda låsobjekt som används av varje instans.

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

beskrivning

I följande exempel används trådar och SyncLock. Så länge instruktionen SyncLock finns är instruktionsblocket ett kritiskt avsnitt och balance blir aldrig ett negativt tal. Du kan kommentera ut instruktionen SyncLock och End SyncLock för att se effekten av att utelämna nyckelordet 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

Kommentarer

Se även