Share via


Instrução SyncLock

Acquires an exclusive lock for a statement block before executing the block.

SyncLock lockobject
    [ block ]
End SyncLock

Parts

  • lockobject
    Required. Expression that evaluates to an object reference.

  • block
    Optional. Block of statements that are to execute when the lock is acquired.

  • End SyncLock
    Terminates a SyncLock block.

Comentários

O SyncLockdedemonstrativo garante que vários threads não não executar o bloco de demonstrativo ao mesmo tempo. SyncLockimpede que cada thread inserindo o bloco até que nenhum outro thread está executando.

The most common use of SyncLock is to protect data from being updated by more than one thread simultaneously. If the statements that manipulate the data must go to completion without interruption, put them inside a SyncLock block.

A statement block protected by an exclusive lock is sometimes called a critical section.

Rules

  • Branching. You cannot branch into a SyncLock block from outside the block.

  • Lock Object Value. The value of lockobject cannot be Nothing. You must create the lock object before you use it in a SyncLock statement.

    You cannot change the value of lockobject while executing a SyncLock block. The mechanism requires that the lock object remain unchanged.

Behavior

  • Mechanism. When a thread reaches the SyncLock statement, it evaluates the lockobject expression and suspends execution until it acquires an exclusive lock on the object returned by the expression. When another thread reaches the SyncLock statement, it does not acquire a lock until the first thread executes the End SyncLock statement.

  • Protected Data. If lockobject is a Shared variable, the exclusive lock prevents a thread in any instance of the class from executing the SyncLock block while any other thread is executing it. This protects data that is shared among all the instances.

    If lockobject is an instance variable (not Shared), the lock prevents a thread running in the current instance from executing the SyncLock block at the same time as another thread in the same instance. This protects data maintained by the individual instance.

  • Acquisition and Release. A SyncLock block behaves like a Try...Finally construction in which the Try block acquires an exclusive lock on lockobject and the Finally block releases it. Because of this, the SyncLock block guarantees release of the lock, no matter how you exit the block. This is true even in the case of an unhandled exception.

  • Framework Calls. The SyncLock block acquires and releases the exclusive lock by calling the Enter and Exit methods of the Monitor class in the System.Threading namespace.

Programming Practices

The lockobject expression should always evaluate to an object that belongs exclusively to your class. You should declare a Private object variable to protect data belonging to the current instance, or a Private Shared object variable to protect data common to all instances.

You should not use the Me keyword to provide a lock object for instance data. If code external to your class has a reference to an instance of your class, it could use that reference as a lock object for a SyncLock block completely different from yours, protecting different data. In this way, your class and the other class could block each other from executing their unrelated SyncLock blocks. Similarly locking on a string can be problematic since any other code in the process using the same string will share the same lock.

You should also not use the Me.GetType method to provide a lock object for shared data. This is because GetType always returns the same Type object for a given class name. External code could call GetType on your class and obtain the same lock object you are using. This would result in the two classes blocking each other from their SyncLock blocks.

Examples

Description

The following example shows a class that maintains a simple list of messages. It holds the messages in an array and the last used element of that array in a variable. The addAnotherMessage procedure increments the last element and stores the new message. Those two operations are protected by the SyncLock and End SyncLock statements, because once the last element has been incremented, the new message must be stored before any other thread can increment the last element again.

Se o simpleMessageList classe compartilhada uma lista de mensagens entre todas as suas instâncias, as variáveis messagesList e messagesLast deve ser declarado como Shared. In this case, the variable messagesLock should also be Shared, so that there would be a single lock object used by every 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

O exemplo a seguir usa os threads e SyncLock. Desde que o SyncLock demonstrativo estiver presente, o bloco de demonstrativo é uma seção crítica e balance nunca se torna um número negativo. Você pode comentar o SyncLock e End SyncLock instruções para ver o efeito de deixando o SyncLock palavra-chave.

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

Consulte também

Referência

System.Threading

Monitor

Segmento de sincronização (C# e Visual Basic)

Conceitos

Threading (C# e Visual Basic)