SyncLock 语句SyncLock Statement

执行块之前获取语句块的排他的锁。Acquires an exclusive lock for a statement block before executing the block.

语法Syntax

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
终止SyncLock块。Terminates a SyncLock block.

备注Remarks

SyncLock语句可确保多个线程不会在同一时间中执行的语句块。The SyncLock statement ensures that multiple threads do not execute the statement block at the same time. SyncLock 阻止每个线程进入块,直到没有其他线程正在执行它。SyncLock prevents each thread from entering the block until no other thread is executing it.

最常用的SyncLock是由多个线程同时更新保护数据。The most common use of SyncLock is to protect data from being updated by more than one thread simultaneously. 如果操作的数据的语句必须转到完成而不发生中断,则将它们放SyncLock块。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. 不能分支到SyncLock阻止其块外部。You cannot branch into a SyncLock block from outside the block.

  • 锁定对象值。Lock Object Value. lockobject不能为NothingThe value of lockobject cannot be Nothing. 必须先将其用于创建的锁对象SyncLock语句。You must create the lock object before you use it in a SyncLock statement.

    无法更改的值lockobject执行时SyncLock块。You cannot change the value of lockobject while executing a SyncLock block. 该机制要求的锁对象保持不变。The mechanism requires that the lock object remain unchanged.

  • 不能使用Await中的运算符SyncLock块。You can't use the Await operator in a SyncLock block.

行为Behavior

  • 机制。Mechanism. 当一个线程到达SyncLock语句,它的计算结果lockobject表达式和挂起执行,直到它将获取由表达式返回的对象上的排他锁。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. 在另一个线程到达SyncLock语句,它并不获取锁直到第一个线程执行End SyncLock语句。When another thread reaches the SyncLock statement, it does not acquire a lock until the first thread executes the End SyncLock statement.

  • 受保护的数据。Protected Data. 如果lockobjectShared变量,防止类的任何实例中的线程执行的排他锁SyncLock阻止其他线程执行时。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.

    如果lockobject是一个实例变量 (不Shared),锁将阻止执行从当前实例中运行的线程SyncLock处的同一实例中的另一个线程在同一时间块。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. 一个SyncLock块的行为类似于Try...Finally在其中构造Try块上获取排他锁lockobjectFinally块释放它。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. 正因为如此,SyncLock块都可确保释放锁,不管您如何退出块。Because of this, the SyncLock block guarantees release of the lock, no matter how you exit the block. 这是甚至在未处理的异常的情况下,则返回 true。This is true even in the case of an unhandled exception.

  • 框架将调用。Framework Calls. SyncLock块将获取并释放通过调用的排他锁EnterExit的方法MonitorSystem.Threading命名空间。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

lockobject表达式应计算结果始终为以独占方式属于您的类的对象。The lockobject expression should always evaluate to an object that belongs exclusively to your class. 应声明Private对象变量来保护属于当前实例的数据或Private Shared对象变量来保护数据普遍适用于所有实例。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.

不应使用Me关键字提供锁定对象实例数据。You should not use the Me keyword to provide a lock object for instance data. 如果您的类的外部代码可以对您的类的实例的引用,它可以使用该引用的锁定对象作为SyncLock块完全不同,如果您保护不同的数据。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. 这样一来,您的类和其他类可能会互相阻塞执行其不相关SyncLock块。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.

您也不应使用Me.GetType方法以提供锁定对象的共享数据。You should also not use the Me.GetType method to provide a lock object for shared data. 这是因为GetType始终返回同一个Type给定的类名称的对象。This is because GetType always returns the same Type object for a given class name. 外部代码可以调用GetType在类上,并获取正在使用的同一个锁对象。External code could call GetType on your class and obtain the same lock object you are using. 这将导致两个类相互阻止其SyncLock块。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. addAnotherMessage过程递增的最后一个元素,并将存储新消息。The addAnotherMessage procedure increments the last element and stores the new message. 这两项操作受SyncLockEnd SyncLock语句,因为后递增的最后一个元素,任何其他线程可以再次增加的最后一个元素之前,必须将存储新消息。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.

如果simpleMessageList类共享其所有实例,这些变量之间的消息的一个列表messagesListmessagesLast将被声明为SharedIf the simpleMessageList class shared one list of messages among all its instances, the variables messagesList and messagesLast would be declared as Shared. 在此情况下,变量messagesLock也应是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

下面的示例使用线程和SyncLockThe following example uses threads and SyncLock. 只要SyncLock语句,语句块就是关键部分和balance永远不会是负数。As long as the SyncLock statement is present, the statement block is a critical section and balance never becomes a negative number. 您可以注释掉SyncLockEnd SyncLock语句,以查看影响省去SyncLock关键字。You can comment out the SyncLock and End SyncLock statements to see the effect of leaving out the SyncLock keyword.

代码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

注释Comments

请参阅See also