어떤 스레드의 작업이 끝나야만 다음 작업을 수행하는 스레드가 필요할 때, Join 메서드를 이용해서 해당 스레드의 작업이 끝날 때까지 기다릴 수 있습니다.
사용 예시
public static void Main()
{
Thread t = new Thread(Wait2Seconds);
t.Start();
t.Join();
Console.WriteLine("나 너를 기다렸어");
}
static void Wait2Seconds()
{
Thread.Sleep(2000);
Console.WriteLine("업무 끝!");
}
업무 끝!
나 너를 기다렸어
그런데 이 Join 메서드는 스레드 풀을 사용할 때에는 사용할 수 없습니다.
스레드 풀은 스레드 사용이 종료되어도 스레드가 반납되지 않기 때문입니다.
이럴 때에는 EventWaitHandle을 사용합니다. 설명은 아래에서!
사용 예시
class Program
{
public static void Main()
{
EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.ManualReset);
Thread t = new Thread(Wait2Seconds);
t.Start(ewh);
ewh.WaitOne();
Console.WriteLine("나 너를 기다렸어");
}
static void Wait2Seconds(object state)
{
EventWaitHandle ewh = state as EventWaitHandle;
Thread.Sleep(2000);
Console.WriteLine("업무 끝!");
ewh.Set();
}
}
업무 끝!
나 너를 기다렸어
EventWaitHandle은 플립플롭처럼 상태가 Non-Signal과 Signal 상태입니다.
Non-Signal 상태에서 Set 함수를 실행하면 Signal 상태가 되고, Signal 상태에서 Reset을 하게 되면 Non-Signal 상태가 됩니다.
스레드가 WaitOne 메서드를 호출하는 시점에 이벤트 객체가 Signal 상태이면 메서드에서 곧바로 제어가 반환되지만, Non-Signal 상태이면 상태가 Signal 로 바뀔때까지 제어를 반환하지 않고 대기합니다.
처음 EventWaitHandle을 선언할 때 false로 초기화했기 때문에 Non-Signal 상태가 됩니다.
그래서 WaitOne을 호출해도 제어를 반환받지 못하고 대기합니다.
그런데 ewh.Set()을 실행하여 상태가 Signal이 되면 제어를 반납받게 됩니다.
이를 이용하여 Join을 사용하지 않고도 스레드풀을 사용하며 스레드 반납을 감지할 수 있습니다.
위 코드에서는 EventWaitHandle(false, EventResetMode.ManualReset) 을 사용하여 초기화했습니다.
여기서 ManualReset은 이 이벤트 객체를 수동으로 초reset하겠다는 것을 의미합니다.
사실 자동으로 리셋할 수도 있는데, 이럴 때에는 AutoReset을 넣어 주면 됩니다.
자동으로 리셋할 경우에는 한 개의 스레드만을 깨우고 다시 Non-Signal 상태로 바뀝니다.
수동으로 하면 여러 개의 스레드를 깨우고 커스텀하게 Non-Signal 상태로 변할 수 있다는 이점이 있습니다.
'Server > C# 비동기와의 전쟁' 카테고리의 다른 글
Task.Run vs await (0) | 2023.11.03 |
---|---|
내가 생각한 비동기 입력은 없었다 (1) | 2023.08.08 |
C# 이벤트 (LUA와 비교) (0) | 2023.06.09 |
[추가필요] 스레드 간 리소스 공유 (0) | 2023.06.02 |