Istruzione SyncLock

Acquisisce un blocco esclusivo per un blocco di istruzioni prima di eseguire il blocco.

Sintassi

SyncLock lockobject  
    [ block ]  
End SyncLock  

Parti

lockobject
Obbligatorio. Espressione che restituisce un riferimento a un oggetto.

block
facoltativo. Blocco di istruzioni da eseguire quando viene acquisito il blocco.

End SyncLock
Termina un SyncLock blocco.

Commenti

L'istruzione SyncLock garantisce che più thread non eseseguono il blocco di istruzioni contemporaneamente. SyncLock impedisce a ogni thread di immettere il blocco fino a quando non viene eseguito alcun altro thread.

L'uso più comune di SyncLock è proteggere i dati da aggiornare contemporaneamente da più thread. Se le istruzioni che modificano i dati devono passare al completamento senza interruzioni, inserirle all'interno di un SyncLock blocco.

Un blocco di istruzioni protetto da un blocco esclusivo viene talvolta chiamato una sezione critica.

Regole

  • Ramificazione. Non è possibile ramo in un SyncLock blocco dall'esterno del blocco.

  • Valore dell'oggetto Lock. Il valore di lockobject non può essere Nothing. È necessario creare l'oggetto lock prima di usarlo in un'istruzione SyncLock .

    Non è possibile modificare il valore di durante l'esecuzione di lockobject un SyncLock blocco. Il meccanismo richiede che l'oggetto lock rimanga invariato.

  • Non è possibile usare l'operatore Await in un SyncLock blocco.

Comportamento

  • Meccanismo. Quando un thread raggiunge l'istruzione SyncLock , valuta l'espressione lockobject e sospende l'esecuzione finché non acquisisce un blocco esclusivo sull'oggetto restituito dall'espressione. Quando un altro thread raggiunge l'istruzione, non acquisisce un blocco finché il primo thread esegue l'istruzione SyncLockEnd SyncLock .

  • Dati protetti. Se lockobject è una variabile, il blocco esclusivo impedisce a un Shared thread in qualsiasi istanza della classe di eseguire il SyncLock blocco durante l'esecuzione di qualsiasi altro thread. In questo modo vengono protetti i dati condivisi tra tutte le istanze.

    Se lockobject è una variabile di istanza (non Shared), il blocco impedisce a un thread in esecuzione nell'istanza corrente di eseguire il SyncLock blocco contemporaneamente a un altro thread nella stessa istanza. Questo consente di proteggere i dati gestiti dall'istanza singola.

  • Acquisizione e rilascio. Un SyncLock blocco si comporta come una Try...Finally costruzione in cui il Try blocco acquisisce un blocco lockobject esclusivo e lo Finally rilascia. A causa di questo, il SyncLock blocco garantisce il rilascio del blocco, indipendentemente dal modo in cui si chiude il blocco. Questo vale anche nel caso di un'eccezione non gestita.

  • Chiamate framework. Il SyncLock blocco acquisisce e rilascia il blocco esclusivo chiamando i Enter metodi e Exit della Monitor classe nello System.Threading spazio dei nomi.

Procedure di programmazione

L'espressione lockobject deve sempre valutare un oggetto che appartiene esclusivamente alla classe. È necessario dichiarare una Private variabile oggetto per proteggere i dati appartenenti all'istanza corrente o una Private Shared variabile oggetto per proteggere i dati comuni a tutte le istanze.

Non è consigliabile usare la parola chiave per specificare un oggetto lock per i dati dell'istanza Me . Se il codice esterno alla classe ha un riferimento a un'istanza della classe, può usare tale riferimento come oggetto lock per un SyncLock blocco completamente diverso dai dati, proteggendo dati diversi. In questo modo, la classe e l'altra classe potrebbero impedire l'esecuzione dei blocchi non correlati SyncLock . Analogamente, il blocco su una stringa può essere problematico poiché qualsiasi altro codice nel processo usando la stessa stringa condividerà lo stesso blocco.

Non è inoltre consigliabile usare il Me.GetType metodo per fornire un oggetto lock per i dati condivisi. Questo perché GetType restituisce sempre lo stesso Type oggetto per un determinato nome di classe. Il codice esterno può chiamare GetType la classe e ottenere lo stesso oggetto lock usato. Ciò comporta il blocco tra le due classi.SyncLock

Esempi

Descrizione

Nell'esempio seguente viene illustrata una classe che gestisce un elenco semplice di messaggi. Contiene i messaggi in una matrice e l'ultimo elemento usato di tale matrice in una variabile. La addAnotherMessage procedura incrementa l'ultimo elemento e archivia il nuovo messaggio. Queste due operazioni sono protette dalle SyncLock istruzioni e End SyncLock , perché dopo l'ultimo elemento è stato incrementato, il nuovo messaggio deve essere archiviato prima che qualsiasi altro thread possa incrementare di nuovo l'ultimo elemento.

Se la simpleMessageList classe ha condiviso un elenco di messaggi tra tutte le relative istanze, le variabili messagesList e messagesLast verranno dichiarate come Shared. In questo caso, la variabile messagesLock deve anche essere Shared, in modo che sia presente un singolo oggetto lock usato da ogni istanza.

Codice

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

Descrizione

Nell'esempio seguente vengono usati thread e SyncLock. Purché l'istruzione SyncLock sia presente, il blocco di istruzioni è una sezione critica e balance non diventa mai un numero negativo. È possibile commentare le SyncLock istruzioni e End SyncLock per visualizzare l'effetto di uscire dalla SyncLock parola chiave.

Codice

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

Commenti

Vedi anche