C# 스레드 동기화 AutoResetEvent와 ManualResetEvent의 이해와 사용법
AutoResetEvent와 ManualResetEvent란 무엇인가?
AutoResetEvent와 ManualResetEvent는 모두 이벤트 시그널링 메커니즘을 제공하는 클래스입니다. 이 클래스들은 스레드 간의 통신을 가능하게 하며, 특정 조건이 충족될 때까지 스레드가 기다리도록 할 수 있습니다. 이 두 클래스의 주요 차이점은 이벤트가 리셋되는 방식에 있습니다.
AutoResetEvent
AutoResetEvent는 하나의 스레드가 이벤트를 기다리다가 이벤트가 신호를 받으면, 해당 스레드는 계속 진행하고 이벤트 상태는 자동으로 리셋됩니다. 이를 통해 다른 스레드가 신호를 받을 수 있도록 합니다. 즉, 이벤트가 한 번 신호를 보내면 자동으로 리셋되어 다음 신호를 기다리게 됩니다.
ManualResetEvent
ManualResetEvent는 신호를 받으면 이벤트 상태를 리셋하지 않고 유지합니다. 이벤트 상태를 수동으로 리셋할 때까지 모든 대기 중인 스레드가 신호를 받을 수 있습니다. 이는 여러 스레드가 동일한 신호를 받아야 할 때 유용합니다.
예제 코드
AutoResetEvent 사용 예제
아래는 AutoResetEvent를 사용하는 간단한 예제입니다:
using System;
using System.Threading;
class Program
{
static AutoResetEvent autoEvent = new AutoResetEvent(false);
static void Main(string[] args)
{
Thread worker = new Thread(Worker);
worker.Start();
Console.WriteLine("Main thread waiting for worker to signal...");
autoEvent.WaitOne();
Console.WriteLine("Main thread received signal from worker.");
worker.Join();
}
static void Worker()
{
Console.WriteLine("Worker thread working...");
Thread.Sleep(2000);
Console.WriteLine("Worker thread signaling completion.");
autoEvent.Set();
}
}
이 예제에서 메인 스레드는 Worker 스레드가 완료될 때까지 기다립니다. Worker 스레드는 작업을 완료한 후 autoEvent.Set()을 호출하여 메인 스레드에게 신호를 보냅니다. 메인 스레드는 신호를 받은 후에 실행을 계속합니다.
ManualResetEvent 사용 예제
아래는 ManualResetEvent를 사용하는 간단한 예제입니다:
using System;
using System.Threading;
class Program
{
static ManualResetEvent manualEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
Thread worker1 = new Thread(Worker);
Thread worker2 = new Thread(Worker);
worker1.Start();
worker2.Start();
Console.WriteLine("Main thread waiting for workers to signal...");
Thread.Sleep(2000);
manualEvent.Set();
worker1.Join();
worker2.Join();
}
static void Worker()
{
Console.WriteLine("Worker thread waiting for signal...");
manualEvent.WaitOne();
Console.WriteLine("Worker thread received signal.");
}
}
이 예제에서 두 개의 Worker 스레드는 manualEvent.WaitOne()을 호출하여 신호를 기다립니다. 메인 스레드는 2초 후 manualEvent.Set()을 호출하여 신호를 보내고, Worker 스레드는 신호를 받고 실행을 계속합니다. ManualResetEvent는 수동으로 리셋될 때까지 모든 대기 중인 스레드에게 신호를 보냅니다.
AutoResetEvent와 ManualResetEvent의 차이점
- 자동 리셋 vs. 수동 리셋:
- AutoResetEvent: 신호를 받은 후 자동으로 리셋됩니다.
- ManualResetEvent: 신호를 받은 후 수동으로 리셋될 때까지 유지됩니다.
- 사용 사례:
- AutoResetEvent: 단일 스레드가 신호를 받고, 다시 대기 상태로 돌아가는 시나리오에 적합합니다.
- ManualResetEvent: 여러 스레드가 동일한 신호를 받아야 하는 시나리오에 적합합니다.
실전 예제: AutoResetEvent를 사용한 스레드 동기화
위의 Lock 클래스를 활용하여 AutoResetEvent를 사용한 스레드 동기화 예제를 다시 작성해보겠습니다.
using System;
using System.Threading;
using System.Threading.Tasks;
class Lock
{
AutoResetEvent _available = new AutoResetEvent(true);
public void Acquire()
{
_available.WaitOne();
// _available.Reset();
}
public void Release()
{
_available.Set();
}
}
class Program
{
static int _num = 0;
static Lock _lock = new Lock();
static void Thread_1()
{
for (int i = 0; i < 10000; i++)
{
_lock.Acquire();
_num++;
_lock.Release();
}
}
static void Thread_2()
{
for (int i = 0; i < 10000; i++)
{
_lock.Acquire();
_num--;
_lock.Release();
}
}
static void Main(string[] args)
{
Task t1 = new Task(Thread_1);
Task t2 = new Task(Thread_2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine($"{_num} 정상적인 종료 !");
}
}
이 예제에서 Lock 클래스는 AutoResetEvent를 사용하여 스레드가 자원을 안전하게 접근할 수 있도록 합니다.
결론
AutoResetEvent와 ManualResetEvent는 C#에서 제공하는 강력한 스레드 동기화 도구입니다. AutoResetEvent는 신호를 받은 후 자동으로 리셋되며, 단일 스레드가 신호를 기다리는 상황에 적합합니다. ManualResetEvent는 수동으로 리셋될 때까지 신호를 유지하며, 여러 스레드가 신호를 기다리는 상황에 적합합니다. 이러한 도구를 적절히 사용하여 멀티스레드 환경에서 효율적인 동기화를 구현할 수 있습니다.
'Programming > C#' 카테고리의 다른 글
C# 멀티스레드 프로그래밍 커스텀 재귀적 락과 스핀락 정책 구현 (0) | 2024.07.01 |
---|---|
C#에서의 동기화 전략: ReadWriteLock의 이해와 활용 (0) | 2024.07.01 |
C# 스레드 제어 Thread.Sleep(0), Thread.Sleep(1), Thread.Yield()의 차이점 (0) | 2024.07.01 |
C# SpinLock 효율적인 스레드 동기화 기법 (0) | 2024.07.01 |
C# 멀티스레딩에서 데드락 문제와 해결 방법 (0) | 2024.07.01 |