Partager via


SyncLock, instruction

Acquiert un verrou exclusif pour un bloc d’instructions avant d’exécuter le bloc.

Syntaxe

SyncLock lockobject  
    [ block ]  
End SyncLock  

Pièces

lockobject
Obligatoire. Expression qui prend la valeur d’une référence d’objet.

block
Optionnel. Bloc d’instructions à exécuter lorsque le verrou est acquis.

End SyncLock
Met fin à un SyncLock bloc.

Remarques

L’instruction SyncLock garantit que plusieurs threads n’exécutent pas le bloc d’instructions en même temps. SyncLock empêche chaque thread d’entrer dans le bloc tant qu’aucun autre thread ne l’exécute.

L’utilisation la plus courante consiste SyncLock à protéger les données contre la mise à jour simultanée de plusieurs threads. Si les instructions qui manipulent les données doivent être terminées sans interruption, placez-les dans un SyncLock bloc.

Un bloc d’instructions protégé par un verrou exclusif est parfois appelé section critique.

Règles

  • Ramification. Vous ne pouvez pas vous brancher dans un SyncLock bloc à partir de l’extérieur du bloc.

  • Valeur de l’objet Lock. La valeur de lockobject ne peut pas être Nothing. Vous devez créer l’objet de verrou avant de l’utiliser dans une SyncLock instruction.

    Vous ne pouvez pas modifier la valeur d’un bloc lors de lockobject l’exécution d’un SyncLock bloc. Le mécanisme exige que l’objet de verrou reste inchangé.

  • Vous ne pouvez pas utiliser l’opérateur Await dans un SyncLock bloc.

Comportement

  • Mécanisme. Lorsqu’un thread atteint l’instruction SyncLock , il évalue l’expression et suspend l’exécution lockobject jusqu’à ce qu’elle acquiert un verrou exclusif sur l’objet retourné par l’expression. Lorsqu’un autre thread atteint l’instruction SyncLock , il n’acquiert pas de verrou tant que le premier thread n’exécute pas l’instruction End SyncLock .

  • Données protégées. S’il lockobject s’agit d’une Shared variable, le verrou exclusif empêche un thread dans une instance de la classe d’exécuter le SyncLock bloc alors que tout autre thread l’exécute. Cela protège les données partagées entre toutes les instances.

    S’il lockobject s’agit d’une variable d’instance (et non Shared), le verrou empêche un thread en cours d’exécution dans l’instance actuelle d’exécuter le SyncLock bloc en même temps qu’un autre thread de la même instance. Cela protège les données conservées par l’instance individuelle.

  • Acquisition et mise en production. Un SyncLock bloc se comporte comme une Try...Finally construction dans laquelle le Try bloc acquiert un verrou exclusif sur lockobject et le Finally bloc le libère. En raison de cela, le SyncLock bloc garantit la libération du verrou, quelle que soit la façon dont vous quittez le bloc. Cela est vrai même dans le cas d’une exception non gérée.

  • Appels d’infrastructure. Le SyncLock bloc acquiert et libère le verrou exclusif en appelant les méthodes et Exit les Enter méthodes de la Monitor classe dans l’espace System.Threading de noms.

Pratiques de programmation

L’expression lockobject doit toujours évaluer un objet qui appartient exclusivement à votre classe. Vous devez déclarer une Private variable objet pour protéger les données appartenant à l’instance actuelle ou une Private Shared variable objet pour protéger les données communes à toutes les instances.

Vous ne devez pas utiliser le Me mot clé pour fournir un objet de verrouillage pour les données d’instance. Si le code externe à votre classe a une référence à une instance de votre classe, il peut utiliser cette référence en tant qu’objet de verrou pour un SyncLock bloc complètement différent du vôtre, protégeant des données différentes. De cette façon, votre classe et l’autre classe peuvent empêcher l’exécution de leurs blocs non liés SyncLock . De même, le verrouillage sur une chaîne peut être problématique, car tout autre code du processus utilisant la même chaîne partagera le même verrou.

Vous ne devez pas également utiliser la Me.GetType méthode pour fournir un objet de verrouillage pour les données partagées. Cela est dû au fait que GetType toujours retourne le même Type objet pour un nom de classe donné. Le code externe peut appeler GetType votre classe et obtenir le même objet de verrouillage que celui que vous utilisez. Cela entraînerait le blocage des deux classes les unes des autres de leurs SyncLock blocs.

Exemples

Descriptif

L’exemple suivant montre une classe qui gère une liste simple de messages. Il contient les messages d’un tableau et le dernier élément utilisé de ce tableau dans une variable. La addAnotherMessage procédure incrémente le dernier élément et stocke le nouveau message. Ces deux opérations sont protégées par les SyncLock instructions et End SyncLock , étant donné qu’une fois le dernier élément incrémenté, le nouveau message doit être stocké avant que tout autre thread puisse incrémenter le dernier élément.

Si la simpleMessageList classe a partagé une liste de messages parmi toutes ses instances, les variables messagesList et messagesLast seraient déclarées en tant que Shared. Dans ce cas, la variable messagesLock doit également être Shared, afin qu’il y ait un seul objet de verrou utilisé par chaque instance.

Code

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

Descriptif

L’exemple suivant utilise des threads et SyncLock. Tant que l’instruction SyncLock est présente, le bloc d’instructions est une section critique et balance ne devient jamais un nombre négatif. Vous pouvez commenter les SyncLock instructions et End SyncLock afficher l’effet de l’abandon du SyncLock mot clé.

Code

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

Commentaires

Voir aussi