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
Necesario. 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.

Comentarios

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 ningún otro subproceso lo ejecute.

El uso más común de es proteger los datos de que varios subprocesos actualicen SyncLock los datos simultáneamente. Si las instrucciones que manipulan los datos deben completarse sin interrupción, pónlas 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 SyncLock un bloque desde fuera del bloque.

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

    No se puede cambiar el valor de lockobject mientras se ejecuta un bloque SyncLock . 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 instrucción , evalúa la expresión y suspende la ejecución hasta que adquiere un bloqueo exclusivo en el objeto SyncLock lockobject devuelto por la expresión. Cuando otro subproceso alcanza SyncLock la instrucción , no adquiere un bloqueo hasta que el primer subproceso ejecuta la instrucción End SyncLock .

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

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

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

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

Prácticas de programación

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

No debe usar la palabra Me 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 bloque completamente diferente del nuestro, protegiendo datos SyncLock diferentes. De esta manera, la clase y la otra clase podrían bloquearse entre sí para que no ejecuten sus bloques no SyncLock relacionados. De forma similar, 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 método Me.GetType para proporcionar un objeto de bloqueo para los datos compartidos. Esto se debe a GetType que siempre devuelve el mismo objeto para un nombre de clase Type determinado. El código externo podría GetType llamar a en la clase y obtener el mismo objeto de bloqueo que está usando. Esto daría lugar a que las dos clases se bloquearan entre sí de sus SyncLock bloques.

Ejemplos

Descripción

En el ejemplo siguiente se muestra una clase que mantiene una lista simple 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 instrucciones y , porque una vez que se ha incrementado el último elemento, el nuevo mensaje debe almacenarse antes de que cualquier otro subproceso pueda volver a incrementar el SyncLock End SyncLock último elemento.

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

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 nunca se convierte en un número balance negativo. Puede comentar las instrucciones SyncLock y para ver el efecto de dejar fuera la palabra clave End SyncLock SyncLock .

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

Consulta también