Compartir a través de


SyncLock (instrucción)

Adquiere un bloqueo exclusivo para un bloque de instrucciones antes de ejecutar el bloque.

Sintaxis

SyncLock lockobject  
    [ block ]  
End SyncLock  

Partes

lockobject
Obligatorio. Expresión que se evalúa como una referencia de objeto.

block
Opcional. Bloque de instrucciones que se van a ejecutar cuando se adquiere el bloqueo.

End SyncLock
Finaliza un SyncLock bloque.

Observaciones

La SyncLock instrucción garantiza que varios subprocesos no ejecuten el bloque de instrucciones al mismo tiempo. SyncLock impide que cada subproceso entre en el bloque hasta que no se ejecute ningún otro subproceso.

El uso más común de es proteger los datos de ser actualizados por más de SyncLock un subproceso simultáneamente. Si las instrucciones que manipulan los datos deben ir a la finalización sin interrupción, colóquelas dentro de un SyncLock bloque.

A veces, un bloque de instrucciones protegido por un bloqueo exclusivo se denomina sección crítica.

Reglas

  • Ramificación. No se puede bifurcar en un SyncLock bloque desde fuera del bloque.

  • Bloquear valor del objeto. El valor de lockobject no puede ser Nothing. Debe crear el objeto lock antes de usarlo en una SyncLock instrucción .

    No se puede cambiar el valor de lockobject mientras se ejecuta un SyncLock bloque. El mecanismo requiere que el objeto de bloqueo permanezca sin cambios.

  • No se puede usar el operador Await en un SyncLock bloque.

Comportamiento

  • Mecanismo. Cuando un subproceso alcanza la SyncLock instrucción , evalúa la lockobject expresión y suspende la ejecución hasta que adquiere un bloqueo exclusivo en el objeto devuelto por la expresión. Cuando otro subproceso llega a la SyncLock instrucción , no adquiere un bloqueo hasta que el primer subproceso ejecuta la End SyncLock instrucción .

  • Datos protegidos. Si lockobject es una Shared variable, el bloqueo exclusivo impide que un subproceso de cualquier instancia de la clase ejecute el SyncLock bloque mientras cualquier otro subproceso lo está ejecutando. Esto protege los datos que se comparten entre todas las instancias.

    Si lockobject es una variable de instancia (no Shared), el bloqueo impide que un subproceso que se ejecute en la instancia actual ejecute el SyncLock bloque al mismo tiempo que otro subproceso de la misma instancia. Esto protege los datos mantenidos por la instancia individual.

  • Adquisición y lanzamiento. Un SyncLock bloque se comporta como una Try...Finally construcción en la que el Try bloque adquiere un bloqueo exclusivo y lockobject el Finally bloque lo libera. Debido a esto, el SyncLock bloque garantiza la liberación del bloqueo, independientemente de cómo salga del bloque. Esto es cierto incluso en el caso de una excepción no controlada.

  • Llamadas de marco. El SyncLock bloque adquiere y libera el bloqueo exclusivo llamando a los Enter métodos y Exit de la Monitor clase en el System.Threading espacio de nombres .

Prácticas de programación

La lockobject expresión siempre debe evaluarse como un objeto que pertenece exclusivamente a la clase . Debe declarar una Private variable de objeto para proteger los datos que pertenecen a la instancia actual o una Private Shared variable de objeto para proteger los datos comunes a todas las instancias.

No debe usar la Me palabra clave para proporcionar un objeto de bloqueo para los datos de instancia. Si el código externo a la clase tiene una referencia a una instancia de la clase, podría usar esa referencia como un objeto de bloqueo para un SyncLock bloque completamente diferente del suyo, protegiendo datos diferentes. De este modo, la clase y la otra clase podrían impedir que se ejecuten sus bloques no relacionados SyncLock . Del mismo modo, el bloqueo en una cadena puede ser problemático, ya que cualquier otro código del proceso que use la misma cadena compartirá el mismo bloqueo.

Tampoco debe usar el Me.GetType método para proporcionar un objeto de bloqueo para los datos compartidos. Esto se debe a que GetType siempre devuelve el mismo Type objeto para un nombre de clase determinado. El código externo podría llamar a GetType en la clase y obtener el mismo objeto de bloqueo que está usando. Esto provocaría que las dos clases se bloquearan entre sí desde sus SyncLock bloques.

Ejemplos

Descripción

En el ejemplo siguiente se muestra una clase que mantiene una lista sencilla de mensajes. Contiene los mensajes de una matriz y el último elemento usado de esa matriz en una variable. El addAnotherMessage procedimiento incrementa el último elemento y almacena el nuevo mensaje. Esas dos operaciones están protegidas por las SyncLock instrucciones y End SyncLock , porque una vez que se ha incrementado el último elemento, el nuevo mensaje debe almacenarse antes de que cualquier otro subproceso pueda incrementar de nuevo el último elemento.

Si la simpleMessageList clase compartió una lista de mensajes entre todas sus instancias, las variables messagesList y messagesLast se declararían como Shared. En este caso, la variable messagesLock también debe ser Shared, por lo que habría un único objeto de bloqueo usado por cada instancia.

Código

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

Descripción

En el ejemplo siguiente se usan subprocesos y SyncLock. Siempre que la SyncLock instrucción esté presente, el bloque de instrucciones es una sección crítica y balance nunca se convierte en un número negativo. Puede comentar las SyncLock instrucciones y End SyncLock para ver el efecto de salir de la SyncLock palabra clave .

Código

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

Comentarios

Consulte también