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
블록이lockobject
에 대한 배타적 잠금을 획득하고Finally
블록이 이를 해제하는Try...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
주석
참고 항목
.NET