共用方式為


SyncLock 語句

在執行 區塊之前,先取得語句區塊的獨佔鎖定。

語法

SyncLock lockobject  
    [ block ]  
End SyncLock  

組件

lockobject
必須的。 評估為對象參考的表達式。

block
選擇性。 取得鎖定時要執行的語句區塊。

End SyncLock
SyncLock終止區塊。

備註

語句 SyncLock 可確保多個線程不會同時執行語句區塊。 SyncLock 防止每個線程進入 區塊,直到沒有其他線程執行它為止。

最常見的用法 SyncLock 是保護數據免於同時由一個以上的線程更新。 如果作數據的語句必須移至完成,而不會中斷,請將它們放在區塊內 SyncLock

受獨佔鎖定保護的語句區塊有時稱為 重要區段

規則

  • 分支。 您無法從 區塊外部分支至 SyncLock 區塊。

  • Lock 物件值。 的值 lockobject 不可以是 Nothing。 在語句中使用 SyncLock 鎖定物件之前,您必須先建立鎖定物件。

    您無法在執行 SyncLock 區塊時變更的值lockobject。 機制要求鎖定物件保持不變。

  • 您無法在 區塊中使用 SyncLockAwait 運算子。

行為

  • 機制。 當線程到達 SyncLock 語句時 lockobject ,它會評估表達式並暫停執行,直到它取得表達式所傳回物件的獨佔鎖定為止。 當另一個線程到達 SyncLock 語句時,它不會取得鎖定,直到第一個線程執行 End SyncLock 語句為止。

  • 受保護的數據。 如果 lockobjectShared 變數,則獨佔鎖定可防止類別的任何實例中的線程在執行區塊時執行 SyncLock 區塊。 這會保護所有實例之間共享的數據。

    如果 lockobject 是實例變數(不是 Shared),鎖定會防止在目前實例中執行的線程與相同實例中的另一個線程同時執行 SyncLock 區塊。 這會保護個別實例所維護的數據。

  • 取得和發行。 SyncLock區塊的行為就像Try...Finally區塊取得獨佔鎖定lockobject的建構Try,而Finally區塊會釋放它。 因此, SyncLock 不論您如何結束區塊,區塊都保證會釋放鎖定。 即使發生未處理的例外狀況,也是如此。

  • 架構呼叫。 區塊SyncLock會藉由在 命名空間中System.Threading呼叫 Enter 類別的 MonitorExit 方法,來取得並釋放獨佔鎖定。

程序設計實務

表達式 lockobject 應該一律評估為專屬於類別的物件。 您應該宣告 Private 物件變數來保護屬於目前實例的數據,或 Private Shared 宣告物件變數來保護所有實例通用的數據。

您不應該使用 Me 關鍵詞來提供實例數據的鎖定物件。 如果類別外部的程式代碼具有類別實例的參考,它可以使用該參考做為與您完全不同的區塊鎖定對象 SyncLock ,保護不同的數據。 如此一來,您的類別和另一個類別可能會互相封鎖,使其無法執行其不相關的 SyncLock 區塊。 同樣地,鎖定字串可能會造成問題,因為進程中使用相同字串的任何其他程式碼都會共用相同的鎖定。

您也不應該使用 Me.GetType 方法來提供共享數據的鎖定物件。 這是因為 GetType 一律會針對指定的類別名稱傳回相同的 Type 物件。 外部程式代碼可以在類別上呼叫 GetType ,並取得您所使用的相同鎖定物件。 這會導致兩個類別彼此封鎖其 SyncLock 區塊。

範例

說明

下列範例顯示維護簡單訊息清單的類別。 它會保存數位中的訊息,以及變數中該陣列的最後一個已使用元素。 此 addAnotherMessage 程式會遞增最後一個專案,並儲存新的訊息。 這兩個作業會受到 SyncLockEnd SyncLock 語句的保護,因為一旦最後一個專案遞增,必須先儲存新的訊息,任何其他線程才能再次遞增最後一個專案。

simpleMessageList如果類別在其所有實體之間共用一份訊息清單,messagesList變數和 messagesLast 會宣告為 Shared。 在此情況下,變數 messagesLock 也應該是 Shared,因此每個實例都會使用單一鎖定物件。

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

說明

下列範例使用線程和 SyncLock。 只要 SyncLock 語句存在,語句區塊就是關鍵區段,而且 balance 永遠不會變成負數。 您可以批注化 SyncLockEnd SyncLock 語句,以查看排除 SyncLock 關鍵詞的效果。

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

評論

另請參閱