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.

    執行 SyncLock 區塊時,您無法變更 lockobject 的值。You cannot change the value of lockobject while executing a SyncLock block. 此機制會要求鎖定物件保持不變。The mechanism requires that the lock object remain unchanged.

  • 您不能在 SyncLock 區塊中使用Await運算子。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 區塊會在 lockobject 上取得獨佔鎖定,而 Finally 區塊則會釋放它。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. 即使是未處理的例外狀況,也是如此。This is true even in the case of an unhandled exception.

  • 架構呼叫。Framework Calls. SyncLock 區塊會藉由呼叫 System.Threading 命名空間中 Monitor 類別的 EnterExit 方法,來取得和釋放獨佔鎖定。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