SyncLock ステートメント
ブロックを実行する前に、ステートメント ブロックの排他ロックを取得します。
構文
SyncLock lockobject
[ block ]
End SyncLock
指定項目
lockobject
必須です。 オブジェクト参照として評価される式。
block
任意。 ロックが取得されたときに実行されるステートメントのブロック。
End SyncLock
SyncLock
ブロックを終了します。
Remarks
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
ブロックがlockobject
に対して排他ロックを取得するTry...Finally
コンストラクションと同様に動作し、Finally
ブロックによって解放されます。 このため、SyncLock
ブロックは、ブロックを終了する方法に関係なく、ロックの解放を保証します。 これは、ハンドルされない例外が発生した場合でも当てはまります。フレームワークの呼び出し。
SyncLock
ブロックは、System.Threading 名前空間のMonitor
クラスのEnter
およびExit
メソッドを呼び出すことによって、排他ロックを取得したり解放したりします。
プログラミング プラクティス
lockobject
式は、常に、クラスに排他的に属しているオブジェクトに評価される必要があります。 現在のインスタンスに属するデータを保護するには Private
オブジェクト変数を宣言し、すべてのインスタンスに共通のデータを保護するには Private Shared
オブジェクト変数を宣言する必要があります。
インスタンス データ用のロック オブジェクトを指定するために、Me
キーワードを使用しないでください。 クラスの外部のコードにクラスのインスタンスへの参照が含まれている場合、その参照を、ユーザーのものとはまったく異なる SyncLock
ブロックのロック オブジェクトとして使用して、さまざまなデータを保護することができます。 このようにして、ユーザーのクラスとその他のクラスは、関連付けられていない SyncLock
ブロックの実行を互いにブロックできます。 同様に、文字列のロックも問題になる可能性があります。同じ文字列を使用するコードがプロセス内に他にも存在した場合、そのコードも同じロックを共有するためです。
また、共有データのロック オブジェクトを指定するために、Me.GetType
メソッドを使用しないでください。 これは、GetType
は常に、指定されたクラス名に対して同じ Type
オブジェクトを返すためです。 外部コードは、クラスで GetType
を呼び出し、使用しているものと同じロック オブジェクトを取得することができます。 これにより、2 つのクラスが SyncLock
ブロックから互いにブロックされることになります。
使用例
説明
次の例では、メッセージの単純なリストを保持するクラスを示します。 これは、メッセージを配列内に保持し、その配列の最後に使用された要素を変数に保持します。 addAnotherMessage
プロシージャは、最後の要素をインクリメントし、新しいメッセージを格納します。 これら 2 つの操作は、SyncLock
および End SyncLock
ステートメントによって保護されます。最後の要素がインクリメントされた後、他のすべてのスレッドが最後の要素を再度インクリメントできるようになる前に、新しいメッセージが格納される必要があるためです。
simpleMessageList
クラスがそのすべてのインスタンス間で 1 つのメッセージ リストを共有している場合、変数 messagesList
および messagesLast
は Shared
として宣言されます。 この場合、変数 messagesLock
も Shared
にして、すべてのインスタンスで 1 つのロック オブジェクトが使用されるようにする必要があります。
コード
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
コメント
関連項目
.NET