SyncLock, instruction
Acquiert un verrou exclusif pour un bloc d’instructions avant l’exécution du bloc.
Syntaxe
SyncLock lockobject
[ block ]
End SyncLock
Éléments
lockobject
Obligatoire. Expression qui prend la valeur d’une référence d’objet.
block
Optionnel. Bloc d’instructions à exécuter quand le verrou est acquis.
End SyncLock
met fin à un bloc SyncLock
.
Notes
L’instruction SyncLock
garantit que le bloc d’instructions n’est pas exécuté par plusieurs threads à la fois. SyncLock
empêche chaque thread d’entrer dans le bloc tant que celui-ci est exécuté par un autre thread.
SyncLock
est le plus souvent utilisé pour empêcher la mise à jour de données par plusieurs threads à la fois. Si les instructions qui manipulent les données doivent s’exécuter jusqu’à leur achèvement sans interruption, placez-les dans un bloc SyncLock
.
Un bloc d’instructions protégé par un verrou exclusif est parfois appelé section critique.
Règles
Création de branches. Vous ne pouvez pas créer de branche dans un bloc
SyncLock
à partir de l’extérieur du bloc.Valeur de l’objet de verrouillage. La valeur de
lockobject
ne peut pas êtreNothing
. Vous devez créer l’objet de verrouillage avant de l’utiliser dans une instructionSyncLock
.Vous ne pouvez pas modifier la valeur de
lockobject
pendant l’exécution d’un blocSyncLock
. Le mécanisme nécessite que l’objet de verrouillage reste inchangé.Vous ne pouvez pas utiliser l’opérateur Await dans un bloc
SyncLock
.
Comportement
Mécanisme. Quand un thread atteint l’instruction
SyncLock
, il évalue l’expressionlockobject
et suspend l’exécution jusqu’à ce qu’il acquière un verrou exclusif sur l’objet retourné par l’expression. Quand un autre thread atteint l’instructionSyncLock
, il n’acquiert pas de verrou tant que le premier thread exécute l’instructionEnd SyncLock
.Données protégées. Si
lockobject
est une variableShared
, le verrou exclusif empêche tout thread (dans n’importe quelle instance de la classe) d’exécuter le blocSyncLock
tant qu’il est exécuté par un autre thread. Cela protège les données partagées entre toutes les instances.Si
lockobject
est une variable d’instance (nonShared
), le verrou empêche tout thread en cours d’exécution dans l’instance actuelle d’exécuter le blocSyncLock
en même temps qu’un autre thread dans la même instance. Cela protège les données gérées par l’instance individuelle.Acquisition et libération. Un bloc
SyncLock
se comporte comme une constructionTry...Finally
dans laquelle le blocTry
acquiert un verrou exclusif surlockobject
et le blocFinally
le libère. Ainsi, le blocSyncLock
garantit la libération du verrou, quelle que soit la façon dont vous quittez le bloc. C’est vrai même dans le cas d’une exception non prise en charge.Appels de framework. Le bloc
SyncLock
acquiert et libère le verrou exclusif en appelant les méthodesEnter
etExit
de la classeMonitor
dans l’espace de noms System.Threading.
Pratiques de programmation
L’expression lockobject
doit toujours prendre la valeur d’un objet qui appartient exclusivement à votre classe. Vous devez déclarer une variable objet Private
pour protéger les données appartenant à l’instance actuelle ou une variable objet Private Shared
pour protéger les données communes à toutes les instances.
Vous ne devez pas utiliser le mot clé Me
pour fournir un objet de verrouillage pour des données d’instance. Si du code externe à votre classe contient une référence à une instance de votre classe, il peut utiliser cette référence comme objet de verrouillage pour un bloc SyncLock
complètement différent du vôtre, protégeant différentes données. Ainsi, votre classe et l’autre classe peuvent s’empêcher mutuellement d’exécuter leurs blocs SyncLock
non liés. De même, le verrouillage sur une chaîne peut être problématique, car tout autre code dans le processus utilisant la même chaîne partagera le même verrou.
Vous ne devez pas non plus utiliser la méthode Me.GetType
pour fournir un objet de verrouillage pour des données partagées. En effet, GetType
retourne toujours le même objet Type
pour un nom de classe donné. Le code externe peut appeler GetType
sur votre classe et obtenir le même objet de verrouillage que celui que vous utilisez. Ainsi, les deux classes s’empêcheront mutuellement d’exécuter leurs blocs SyncLock
.
Exemples
Description
L’exemple suivant montre une classe qui gère une simple liste de messages. Elle stocke les messages dans un tableau et le dernier élément utilisé de ce tableau dans une variable. La procédure addAnotherMessage
incrémente le dernier élément et stocke le nouveau message. Ces deux opérations sont protégées par les instructions SyncLock
et End SyncLock
, car après l’incrémentation du dernier élément, le nouveau message doit être stocké avant qu’un autre thread puisse à nouveau l’incrémenter.
Si la classe simpleMessageList
partageait une liste de messages entre toutes ses instances, les variables messagesList
et messagesLast
seraient déclarées comme Shared
. Dans ce cas, la variable messagesLock
devrait également être Shared
pour qu’un seul objet de verrouillage soit 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
Description
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 instructions SyncLock
et End SyncLock
pour voir ce qui se passe quand vous omettez le mot clé SyncLock
.
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