SyncLock 陳述式
在執行區塊之前,請先取得陳述式區塊的獨佔鎖定。
語法
SyncLock lockobject
[ block ]
End SyncLock
組件
lockobject
必要。 評估為物件參考的運算式。
block
選擇性。 取得鎖定時,要執行的陳述式區塊。
End SyncLock
終止 SyncLock
區塊。
備註
SyncLock
陳述式可確保不會出現多個執行緒同時執行該陳述式區塊的情況。 SyncLock
不會讓任一執行緒進入區塊,直到沒有任何其他執行緒在執行該區塊為止。
SyncLock
最常見的用法,是保護資料免於同時由一個以上的執行緒進行更新。 如果運用資料的陳述式必須不中斷地完成,請將這些陳述式置於 SyncLock
區塊內。
受獨佔鎖定所保護的陳述式區塊,有時稱為「關鍵區段」。
規則
分支。 您無法從區塊之外,分支到
SyncLock
區塊。鎖定物件值。
lockobject
的值不得為Nothing
。 您必須先建立鎖定物件,然後才能在SyncLock
陳述式中使用鎖定物件。執行
SyncLock
區塊時,您無法變更lockobject
的值。 該機制要求鎖定物件要保持不變。您在
SyncLock
區塊中無法使用 Await 運算子。
行為
機制。 當執行緒到達
SyncLock
陳述式時,會評估lockobject
運算式並暫停執行,直到它取得由運算式所傳回對該物件的獨佔鎖定為止。 當另一個執行緒到達SyncLock
陳述式時,要等到第一個執行緒執行End SyncLock
陳述式之後,才會取得鎖定。受保護的資料。 如果
lockobject
是Shared
變數,則獨佔鎖定可避免該類別任一執行個體中的執行緒,在任何其他執行緒還在執行這區塊時,即執行SyncLock
區塊。 如此可以保護所有執行個體之間共用的資料。如果
lockobject
是執行個體變數 (而非Shared
),該鎖定會避免目前執行個體中所執行的執行緒,與相同執行個體中的另一個執行緒,同時執行SyncLock
區塊。 如此可以保護由個別執行個體所維護的資料。取得和釋出。
SyncLock
區塊的行為類似於Try...Finally
建構函式,Try
區塊會取得lockobject
的獨佔鎖定,而Finally
區塊會進行釋出。 因此,不論您如何結束SyncLock
區塊,該區塊都保證一定會釋出鎖定。 即使發生未處理的例外狀況,也是如此。架構呼叫。
SyncLock
區塊會藉由在 System.Threading 命名空間中呼叫Monitor
類別的方法Enter
和Exit
,來取得以及釋出獨佔鎖定。
程式設計實務
運算式 lockobject
應該一律評估為專屬於您類別的物件。 您應該宣告 Private
物件變數,來保護屬於目前執行個體的資料,或是宣告 Private Shared
物件變數,來保護所有執行個體通用的資料。
您不應該使用 Me
關鍵字,為執行個體資料提供鎖定物件。 如果您類別外部的程式碼,會參考您類別的執行個體,則程式碼可以為與您的區塊完全不同之 SyncLock
區塊,使用該參考作為鎖定物件,來保護不同的資料。 如此一來,您的類別和另一個類別就可以封鎖彼此,使對方無法執行與其不相關的 SyncLock
區塊。 同樣地,鎖定字串可能會造成問題,因為使用相同字串的處理序中,任一其他程式碼,都共用相同的鎖定。
您也不應該使用 Me.GetType
方法,來為共用資料提供鎖定物件。 這是因為 GetType
一律會針對指定的類別名稱,傳回相同的 Type
物件。 外部程式碼可以對您的類別,呼叫 GetType
,並取得您所使用的相同鎖定物件。 如此會導致兩個類別將彼此封鎖在他們的 SyncLock
區塊之外。
範例
描述
下列範例展示維護一份簡單訊息清單的類別。 它會保存陣列中的訊息,以及變數中該陣列最後使用的一個元素。 此 addAnotherMessage
程序會遞增最後一個元素,並儲存新的訊息。 這兩個作業受到 SyncLock
和 End SyncLock
陳述式的保護,因為一旦遞增最後一個元素之後,必須先儲存新的訊息,其他任何執行緒才能再次遞增最後一個元素。
如果 simpleMessageList
類別在其所有執行個體之間共用一份訊息清單,則會將 messagesList
和 messagesLast
變數宣告為 Shared
。 在此情況下,變數 messagesLock
也應該是 Shared
,如此一來,每個執行個體都會使用單一的鎖定物件。
代碼
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
絶對不會變成負數。 您可以將 SyncLock
和 End SyncLock
陳述式變成註解,以查看排除 SyncLock
關鍵字的效果。
程式碼
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