고급 동기화 기술
업데이트: 2007년 11월
다중 스레드 응용 프로그램에서는 종종 대기 핸들과 모니터 개체를 사용하여 여러 개의 스레드를 동기화합니다. 이 단원에서는 스레드를 동기화할 때 .NET Framework 클래스인 AutoResetEvent, Interlocked, ManualResetEvent, Monitor, Mutex, ReaderWriterLock, Timer, WaitHandle을 사용하는 방법을 설명합니다.
대기 핸들
대기 핸들은 특정 스레드의 상태를 다른 스레드에 알리는 개체입니다. 스레드에서는 대기 핸들을 사용하여 해당 스레드에서 리소스를 단독으로 사용해야 한다는 것을 다른 스레드에 알릴 수 있습니다. 그러면 다른 스레드에서는 대기 핸들이 더 이상 사용되지 않을 때까지 기다렸다가 리소스를 사용해야 합니다. 대기 핸들의 상태에는 signaled와 nonsignaled의 두 가지가 있습니다. 대기 핸들이 어떤 스레드에 의해서도 소유되지 않은 경우 그 대기 핸들을 signaled 상태에 있다고 합니다. 대기 핸들이 특정 스레드에 의해 소유된 경우 그 대기 핸들을 nonsignaled 상태에 있다고 합니다.
스레드에서는 WaitOne, WaitAny 또는 WaitAll 등의 대기 메서드 중 하나를 호출하여 대기 핸들의 소유권을 요청합니다. 대기 메서드는 개별 스레드의 Join 메서드와 유사한 블로킹 호출입니다.
다른 스레드에서 대기 핸들을 소유하고 있지 않으면 이 호출은 즉시 True를 반환하고, 대기 핸들은 nonsignaled 상태로 바뀌며, 대기 핸들을 소유하는 스레드는 계속 실행됩니다.
스레드에서 대기 핸들의 대기 메서드 중 하나를 호출했지만 해당 대기 핸들을 다른 스레드에서 소유하는 경우, 호출하는 스레드는 지정된 시간 동안 대기(제한 시간이 지정된 경우)하거나 다른 스레드에서 대기 핸들을 해제할 때까지 무기한 대기(제한 시간이 지정되지 않은 경우)합니다. 제한 시간이 지정된 경우 제한 시간이 만료되기 전에 대기 핸들이 해제되면 이 호출은 True를 반환합니다. 그렇지 않고 제한 시간이 만료되면 대기하는 호출은 False를 반환하고 호출하는 스레드는 계속 실행됩니다.
대개 핸들을 소유하는 스레드는 작업이 완료되었거나 대기 핸들이 더 이상 필요하지 않으면 Set 메서드를 호출합니다. 다른 스레드에서는 Reset 메서드를 호출하거나 WaitOne, WaitAny 또는 WaitAll을 호출하고 스레드에서 Set을 호출할 때까지 대기하여 대기 핸들의 상태를 nonsignaled로 다시 설정할 수 있습니다. AutoResetEvent 핸들은 단일 대기 스레드가 해제된 후 시스템에 의해 자동으로 nonsignaled로 다시 설정됩니다. 대기 중인 스레드가 없으면 이벤트 개체는 signaled 상태로 계속 남아 있습니다.
Visual Basic에서 일반적으로 사용되는 대기 핸들에는 뮤텍스 개체, ManualResetEvent 및 AutoResetEvent의 세 종류가 있습니다. 뒤에 있는 두 개는 동기화 이벤트라고도 합니다.
뮤텍스 개체
뮤텍스 개체는 한 번에 하나의 스레드에서만 소유할 수 있는 동기화 개체입니다. "뮤텍스"라는 이름은 뮤텍스 개체의 소유권이 상호 배타적(mutually exclusive)이라는 데서 비롯된 것입니다. 스레드에서는 리소스를 단독으로 사용해야 할 경우에 뮤텍스 개체의 소유권을 요청합니다. 항상 한 스레드에서만 뮤텍스 개체를 소유할 수 있으므로 다른 스레드에서 리소스를 사용하려면 뮤텍스 개체의 소유권을 기다려야 합니다.
WaitOne 메서드를 사용하면 호출하는 스레드에서 뮤텍스 개체의 소유권을 기다리게 됩니다. 뮤텍스 개체를 소유하는 스레드가 정상적으로 종료되면 뮤텍스 개체의 상태는signaled로 설정되고 다음 대기 스레드에서 소유권을 받게 됩니다.
동기화 이벤트
동기화 이벤트는 어떤 사항이 발생했거나 리소스가 사용 가능함을 다른 스레드에 알립니다. 이벤트 동기화는 "이벤트"라는 단어를 포함하고 있기는 하지만 다른 Visual Basic 이벤트와는 달리 실제 대기 핸들입니다. 다른 대기 핸들과 마찬가지로 동기화 이벤트에도 signaled와 nonsignaled라는 두 가지 상태가 있습니다.
동기화 이벤트의 대기 메서드 중 하나를 호출하는 스레드는 다른 스레드에서 Set 메서드를 호출하여 이벤트를 알릴 때까지 대기해야 합니다. 동기화 이벤트 클래스에는 ManualResetEvent 및 AutoResetEvent의 두 가지가 있습니다.
스레드에서는 Set 메서드를 사용하여 ManualResetEvent 인스턴스의 상태를 signaled로 설정합니다. 또한 스레드에서는 Reset 메서드를 사용할 경우 또는 대기하는 WaitOne 호출에 제어가 반환될 때 ManualResetEvent 인스턴스의 상태를 nonsignaled로 설정합니다.
AutoResetEvent 클래스의 인스턴스는 Set을 통해 signaled로 설정될 수 있지만 이 인스턴스는 대기 스레드에서 이벤트가 signaled 상태가 되었다는 알림을 받는 즉시 자동으로 nonsignaled 상태로 돌아갑니다.
모니터 개체 및 SyncLock
모니터 개체를 사용하면 코드 블록이 다른 스레드에서 실행되고 있는 코드에 의해 중단되지 않고 실행되도록 할 수 있습니다. 즉, 동기화된 코드 블록의 코드가 완료되기 전까지는 다른 스레드의 코드가 실행되지 않습니다.
예를 들어, 데이터를 반복적, 비동기적으로 읽어서 결과를 표시하는 프로그램이 있다고 가정합니다. 이 경우 선점형 멀티태스킹을 사용하는 운영 체제에서는 다른 스레드가 실행될 시간을 주기 위해 운영 체제에서 실행 중인 스레드를 중단할 수 있습니다. 동기화를 사용하지 않는 경우에는 데이터가 표시되어 있는 동안 해당 데이터를 나타내는 개체가 다른 스레드에 의해 수정되면 부분적으로 업데이트된 데이터를 볼 수 있습니다. 모니터 개체를 사용하면 코드 섹션이 중단되지 않고 실행됩니다. Visual Basic에서는 모니터 개체에 대한 액세스를 단순화하기 위한 SyncLock 및 End SyncLock 문을 제공합니다. Visual C#에서는 Lock 키워드를 같은 방법으로 사용합니다.
참고: |
---|
개체에 대한 액세스 잠금은 동일한 개체 인스턴스의 SyncLock 블록 내에 액세스 코드가 들어 있는 경우에만 잠겨집니다. |
SyncLock 문에 대한 자세한 내용은 SyncLock 문을 참조하십시오.
Interlocked 클래스
Interlocked 클래스의 메서드를 사용하면 여러 스레드에서 같은 값을 동시에 업데이트하거나 비교하려고 할 때 발생할 수 있는 문제를 방지할 수 있습니다. 이 클래스의 메서드를 사용하면 모든 스레드에서 값을 안전하게 늘리거나, 줄이거나, 교환하거나, 비교할 수 있습니다. 다음 예제에서는 Increment 메서드를 사용하여 개별 스레드에서 실행되는 프로시저가 공유하는 변수를 늘리는 방법을 보여 줍니다.
Sub ThreadA(ByRef IntA As Integer)
System.Threading.Interlocked.Increment(IntA)
End Sub
Sub ThreadB(ByRef IntA As Integer)
System.Threading.Interlocked.Increment(IntA)
End Sub
ReaderWriter 잠금
일부 경우에는 데이터를 쓰고 있을 때만 리소스를 잠그고 데이터를 업데이트하지 않을 때는 여러 클라이언트에서 동시에 데이터를 읽을 수 있도록 할 수 있습니다. ReaderWriterLock 클래스를 사용하면 스레드에서 리소스를 수정하는 동안은 리소스를 단독으로 사용하고 리소스를 읽을 때는 여러 스레드에서 동시에 사용하도록 할 수 있습니다. ReaderWriter 잠금은 해당 스레드에서 데이터를 업데이트할 필요가 없는 경우에도 다른 스레드를 대기하도록 만드는 단독 잠금 대신 사용할 수 있는 유용한 기능입니다.
교착 상태
스레드 동기화는 다중 스레드 응용 프로그램에서 매우 중요하지만 여러 스레드가 서로를 대기하여 응용 프로그램이 중지되는 deadlock이 발생할 위험이 항상 존재합니다. 교착 상태는 교차로에서 자동차들이 서로 다른 자동차가 가기를 기다리며 모두 멈춰있는 상황과 비슷합니다. 따라서 교착 상태를 방지하는 것이 중요하며 이를 위해서는 철저한 계획을 세워야 합니다. 종종 코딩을 시작하기 전에 다중 스레드 응용 프로그램의 다이어그램을 작성하면 교착 상태를 예측할 수 있습니다.