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

C# Task 기본 동작과 스레드 실행 시나리오 이해

by 공부봇 2025. 1. 17.
반응형

이 코드는 C#에서 태스크(Task)를 사용하여 멀티스레드 환경에서 연산을 수행하는 기본적인 예제를 보여줍니다. 코드를 분석하고 스레드 풀(Thread Pool)과 메인 스레드에서 실행되는 태스크의 차이를 교육용으로 설명하겠습니다.


코드 구성 및 주요 흐름

1. CreateTask 메서드

static Task<int> CreateTask(string name)
{
    return new Task<int>(() => TaskMethod(name));
}
  • 이 메서드는 태스크를 생성합니다.
  • 태스크는 Task<int> 타입으로 반환되며, 내부적으로 TaskMethod를 실행합니다.
  • 태스크는 생성만 되며, 실행은 호출자가 결정합니다 (Start()나 RunSynchronously()를 호출해야 실행됩니다).

2. TaskMethod 메서드

static int TaskMethod(string name)
{
    Console.WriteLine("Task '{0}' is running on a thread id {1}. Is thread pool thread: {2}", 
        name,
        Thread.CurrentThread.ManagedThreadId,
        Thread.CurrentThread.IsThreadPoolThread);

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

    return 42;
}
  • 이 메서드는 태스크가 수행할 작업입니다.
  • 출력 내용:
    • 현재 실행 중인 스레드의 ID (Thread.ManagedThreadId).
    • 실행 중인 스레드가 **스레드 풀(Thread Pool)**에서 실행되는지 여부 (Thread.IsThreadPoolThread).
  • 태스크는 2초간 멈춘 후 정수 42를 반환합니다.

3. Main 메서드

static void Main(string[] args)
{
    TaskMethod("Main Thread Task");

    Task<int> task = CreateTask("Task 1");
    task.Start();
    int result = task.Result;
    Console.WriteLine("Result is: {0}", result);

    task = CreateTask("Task 2");
    task.RunSynchronously(); 
    result = task.Result;
    Console.WriteLine("Result is: {0}", result);

    task = CreateTask("Task 3");
    task.Start();

    while (!task.IsCompleted)
    {
        Console.WriteLine(task.Status);
        Thread.Sleep(TimeSpan.FromSeconds(0.5));
    }

    Console.WriteLine(task.Status);
    result = task.Result;
    Console.WriteLine("Result is: {0}", result);
}
  • 이 메서드는 태스크 생성, 실행, 결과 확인의 여러 시나리오를 보여줍니다.
  • 각 시나리오를 순서대로 살펴보겠습니다.

시나리오 분석

1. 직접 호출 (TaskMethod)

TaskMethod("Main Thread Task");
  • 동작:
    • TaskMethod가 태스크 없이 직접 호출됩니다.
    • 메인 스레드에서 실행되며, 스레드 풀과 관련이 없습니다.
  • 출력 예시:
    Task 'Main Thread Task' is running on a thread id 1. Is thread pool thread: False
    

2. 태스크 생성 후 Start로 실행

Task<int> task = CreateTask("Task 1");
task.Start();
int result = task.Result;
Console.WriteLine("Result is: {0}", result);
  • 동작:
    • 태스크 Task 1이 생성되고 Start()로 실행됩니다.
    • 실행은 스레드 풀에서 이루어집니다.
    • task.Result는 태스크의 결과를 가져옵니다. 결과를 가져올 때까지 호출자는 대기합니다.
  • 출력 예시:
    Task 'Task 1' is running on a thread id 4. Is thread pool thread: True
    Result is: 42
    

3. 태스크를 동기적으로 실행 (RunSynchronously)

task = CreateTask("Task 2");
task.RunSynchronously();
result = task.Result;
Console.WriteLine("Result is: {0}", result);
  • 동작:
    • RunSynchronously()는 태스크를 현재 스레드(메인 스레드)에서 실행합니다.
    • 스레드 풀을 사용하지 않고 메인 스레드에서 실행됩니다.
    • 동기적으로 실행되므로 호출자가 태스크 종료를 기다릴 필요가 없습니다.
  • 출력 예시:
    Task 'Task 2' is running on a thread id 1. Is thread pool thread: False
    Result is: 42
    

4. 태스크 상태 확인

task = CreateTask("Task 3");
task.Start();

while (!task.IsCompleted)
{
    Console.WriteLine(task.Status);
    Thread.Sleep(TimeSpan.FromSeconds(0.5));
}

Console.WriteLine(task.Status);
result = task.Result;
Console.WriteLine("Result is: {0}", result);
  • 동작:
    • Task 3을 실행하고 상태를 확인하며, 완료될 때까지 루프에서 대기합니다.
    • task.Status는 태스크 상태를 나타냅니다. 상태는 다음 중 하나일 수 있습니다:
      • WaitingToRun: 실행 대기 중.
      • Running: 실행 중.
      • RanToCompletion: 완료됨.
  • 출력 예시:
    WaitingToRun
    Running
    Running
    RanToCompletion
    Result is: 42
    

스레드 풀과 메인 스레드의 차이점

특징 스레드 풀(Thread Pool) 메인 스레드(Main Thread)

실행 환경 Task.Start() 또는 Task.Run() 사용 시 실행. 프로그램의 주 실행 스레드.
스레드 ID 스레드 풀에서 생성된 스레드 ID 사용. 항상 ID 1.
IsThreadPoolThread True. False.
사용 목적 백그라운드 태스크 처리, 비동기 작업. UI 업데이트 및 주요 작업 흐름 관리.
실행 방식 스레드 풀이 관리하며, 비동기적으로 실행. 동기적 실행, 현재 스레드에서 수행.

코드의 주요 포인트

  1. 태스크 생성과 실행:
    • 태스크는 생성 후 명시적으로 Start()나 RunSynchronously()를 호출해야 실행됩니다.
  2. 스레드 풀과 메인 스레드:
    • 태스크는 스레드 풀에서 실행될 수 있지만, RunSynchronously로 메인 스레드에서 실행 가능.
  3. 태스크 상태 관리:
    • task.Status를 통해 태스크의 상태를 실시간으로 확인할 수 있습니다.
  4. 결과 처리:
    • task.Result는 태스크 결과를 반환하지만, 태스크가 완료되지 않은 경우 대기합니다.

추가 학습

  1. async/await 기반 비동기 프로그래밍:
    • 태스크와 잘 어우러지는 C# 비동기 프로그래밍 패턴.
  2. 병렬 처리:
    • Task.WhenAll 또는 Task.WhenAny를 사용하여 여러 태스크를 병렬로 실행.

이 코드는 태스크의 동작 원리를 이해하는 데 유용한 예제입니다. 추가적으로 궁금한 점이 있다면 언제든 질문해주세요! 😊

반응형