본문 바로가기
C#/쓰레드

C# `Thread`와 `ThreadPool`의 차이점 및 델리게이트 비동기 호출 이해

by 공부봇 2025. 1. 16.
반응형
    internal class Program
    {
        private delegate string RunOnThreadPool(out int threadId);

        private static void Callback(IAsyncResult ar)
        {
            Console.WriteLine("Starting a callback...");
            Console.WriteLine("State passed to a callback: {0}", ar.AsyncState);
            Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);
            Console.WriteLine("Thread pool worker thread id: {0}", Thread.CurrentThread.ManagedThreadId);
        }

        private static string Test(out int threadId)
        {
            Console.WriteLine("Starting...");
            Console.WriteLine("Is thread pool thread: {0}", Thread.CurrentThread.IsThreadPoolThread);

            Thread.Sleep(TimeSpan.FromSeconds(2));

            threadId = Thread.CurrentThread.ManagedThreadId;
            
            return string.Format("Thread pool worker thread id was:{0}", threadId);
        }

        static void Main(string[] args)
        {
            int threadId = 0;
            RunOnThreadPool poolDelegate = Test;

            var t = new Thread(() => Test(out threadId));
            t.Start();
            t.Join();

            Console.WriteLine("Thread id: {0}", threadId);
            IAsyncResult r = poolDelegate.BeginInvoke(out threadId, Callback, "a delegate asynchronous call");
            r.AsyncWaitHandle.WaitOne();

            string result = poolDelegate.EndInvoke(out threadId, r);
            Console.WriteLine("Thread pool worker thread id: {0}", threadId);
            Console.WriteLine(result);
            Thread.Sleep(TimeSpan.FromSeconds(2));  
        }
    }

 

코드 분석 및 설명

이 코드는 C#의 델리게이트와 비동기 프로그래밍의 동작 방식을 보여주는 예제입니다. 특히 Thread와 ThreadPool에서 실행되는 작업의 차이점과 델리게이트를 사용해 비동기 호출을 처리하는 방법을 설명합니다. 주요 구성 요소를 단계적으로 살펴보고, 빌드 결과와 함께 자세히 설명하겠습니다.


1. 주요 구성 요소 설명

1.1 델리게이트 정의

private delegate string RunOnThreadPool(out int threadId);
  • RunOnThreadPool은 반환 값이 string이고, out 매개변수로 int threadId를 가지는 델리게이트입니다.
  • 이 델리게이트는 Test 메서드를 호출하기 위해 사용됩니다.

1.2 Callback 메서드

private static void Callback(IAsyncResult ar)
  • 델리게이트 비동기 호출의 콜백 메서드로 사용됩니다.
  • IAsyncResult를 받아, 다음 정보를 출력합니다:
    • 콜백의 상태 (ar.AsyncState)
    • 현재 스레드가 **스레드 풀(Thread Pool)**에서 실행되는지 여부
    • 현재 스레드의 ID

1.3 Test 메서드

private static string Test(out int threadId)
  • Test 메서드는 델리게이트의 대상 메서드로 사용됩니다.
  • 주요 기능:
    1. 시작 메시지와 현재 스레드가 스레드 풀에서 실행되는지 여부를 출력.
    2. 2초 동안 대기 (Thread.Sleep).
    3. 현재 스레드의 ID를 반환하고, 이 값을 out 매개변수로 전달.
    4. 실행 결과로 스레드 정보를 담은 문자열 반환.

1.4 Main 메서드

static void Main(string[] args)
  • 이 프로그램의 진입점으로, 다음 작업을 수행합니다:
    1. 새로운 Thread를 생성하여 Test를 실행.
    2. 델리게이트를 통해 비동기 방식으로 Test를 호출하고, 콜백 메서드를 실행.
    3. Thread와 ThreadPool의 ID를 비교하고, 실행 순서를 확인.

2. 실행 과정 분석

2.1 새로운 Thread에서 실행

var t = new Thread(() => Test(out threadId));
t.Start();
t.Join();
Console.WriteLine("Thread id: {0}", threadId);
  • 새로운 Thread를 생성하여 Test를 실행합니다.
  • Thread.Join을 통해 스레드가 종료될 때까지 대기합니다.
  • Test 메서드는 스레드 풀이 아닌 독립적인 스레드에서 실행되므로, 출력되는 Thread id는 스레드 풀의 ID와 다릅니다.

2.2 델리게이트의 비동기 호출

IAsyncResult r = poolDelegate.BeginInvoke(out threadId, Callback, "a delegate asynchronous call");
r.AsyncWaitHandle.WaitOne();
  • BeginInvoke를 사용해 비동기 방식으로 Test를 호출합니다.
  • 비동기 호출은 스레드 풀에서 실행되며, 작업이 완료되면 Callback 메서드가 호출됩니다.
  • r.AsyncWaitHandle.WaitOne()는 호출이 완료될 때까지 대기합니다.

2.3 Callback 메서드

  • 비동기 호출이 완료된 후 실행됩니다.
  • 현재 스레드가 스레드 풀에서 실행 중인지와 스레드 ID를 출력합니다.

2.4 델리게이트 결과 수집

string result = poolDelegate.EndInvoke(out threadId, r);
Console.WriteLine("Thread pool worker thread id: {0}", threadId);
Console.WriteLine(result);
  • EndInvoke를 호출해 비동기 호출 결과를 수집합니다.
  • 최종적으로 스레드 풀에서 실행된 작업의 결과를 출력합니다.

3. 예상 출력 결과

Starting...
Is thread pool thread: False
Thread id: 3
Starting...
Is thread pool thread: True
Starting a callback...
State passed to a callback: a delegate asynchronous call
Is thread pool thread: True
Thread pool worker thread id: 4
Thread pool worker thread id: 4
Thread pool worker thread id was:4

출력 분석

  1. Thread에서 실행:
    • "Starting..."과 함께 "Is thread pool thread: False"가 출력됩니다.
    • 독립적인 Thread에서 실행되므로, 스레드 풀과 관련이 없습니다.
  2. 비동기 호출 실행:
    • "Starting..."과 "Is thread pool thread: True"가 출력됩니다.
    • 스레드 풀에서 작업이 실행되었음을 확인할 수 있습니다.
  3. 콜백 실행:
    • Callback 메서드가 호출되며, 스레드 풀에 대한 정보와 상태가 출력됩니다.
  4. 결과 출력:
    • EndInvoke를 통해 스레드 풀에서 실행된 작업 결과와 ID를 확인합니다.

4. 학습 포인트

  1. Thread vs. ThreadPool
    • Thread는 독립적인 스레드를 생성하여 작업을 실행.
    • ThreadPool은 시스템에서 관리하는 스레드 풀에서 스레드를 재사용.
    • 스레드 풀은 자원을 효율적으로 사용하며, 비동기 호출과 함께 사용하기 적합.
  2. 델리게이트의 비동기 호출
    • BeginInvoke와 EndInvoke를 통해 델리게이트를 비동기적으로 호출.
    • Callback 메서드를 통해 호출 완료 후 작업 처리.
  3. out 매개변수
    • 메서드 호출 후, 호출한 쪽에서 값을 사용할 수 있도록 데이터 전달.
  4. 스레드 간 동작 차이 이해
    • Thread와 ThreadPool에서 실행되는 작업의 차이를 실험적으로 확인 가능.

 

반응형