스레드와 태스크

스레드와 태스크

Reflection
Published

May 17, 2025

Abstract

ThreadTask는 비동기 프로그래밍을 위한 두 가지 주요 도구입니다. Thread는 직접 스레드를 관리하고 제어하는 방법을 제공하며, Task는 비동기 작업을 쉽게 처리할 수 있도록 도와줍니다. asyncawait는 비동기 코드를 더 읽기 쉽게 만들어주며, 비동기 프로그래밍의 기본 개념을 이해하는 데 도움이 됩니다.

프로세스와 스레드

스레드 시작하기

C#에서는 System.Threading.Thread 클래스를 사용하여 새로운 스레드를 시작할 수 있습니다.

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        Thread t = new Thread(() => Console.WriteLine("새 스레드에서 실행"));
        t.Start();
        Console.WriteLine("메인 스레드에서 실행");
    }
}

스레드 임의로 종료하기

Thread.Abort()는 더 이상 권장되지 않으며, 일반적으로 스레드 내부에서 종료 조건을 체크하도록 설계합니다.

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        bool stop = false;
        Thread t = new Thread(() =>
        {
            while (!stop)
            {
                Console.WriteLine("작업 중...");
                Thread.Sleep(500);
            }
            Console.WriteLine("스레드 종료");
        });
        t.Start();
        Thread.Sleep(2000);
        stop = true;
    }
}

스레드의 일생과 상태 변화

스레드는 다음과 같은 상태를 가집니다: Unstarted, Running, WaitSleepJoin, Suspended, Stopped.

Thread t = new Thread(SomeMethod);
Console.WriteLine(t.ThreadState); // Unstarted
t.Start();
Console.WriteLine(t.ThreadState); // Running 또는 WaitSleepJoin

인터럽트: 스레드를 임의로 종료하는 다른 방법

Thread.Interrupt()를 사용하면 Thread.Sleep이나 Wait 중인 스레드를 예외를 발생시켜 종료시킬 수 있습니다.

Thread t = new Thread(() =>
{
    try
    {
        Thread.Sleep(5000);
    }
    catch (ThreadInterruptedException)
    {
        Console.WriteLine("인터럽트로 인해 스레드 종료");
    }
});
t.Start();
Thread.Sleep(1000);
t.Interrupt();

스레드 간 동기화

lock, Monitor, Mutex, Semaphore, AutoResetEvent 등의 동기화 도구를 사용할 수 있습니다.

class Counter
{
    private int count = 0;
    private object lockObj = new object();

    public void Increment()
    {
        lock (lockObj)
        {
            count++;
        }
    }
}

Task와 Task 그리고 Parallel

System.Threading.Tasks.Task 클래스

Task 클래스는 작업 단위를 비동기적으로 실행할 수 있도록 도와줍니다.

using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        Task t = Task.Run(() => Console.WriteLine("Task 실행 중"));
        t.Wait();
    }
}

코드의 비동기 실행 결과를 주는 Task 클래스

Task<TResult>는 결과를 반환하는 비동기 작업을 표현합니다.

Task<int> t = Task.Run(() =>
{
    return 42;
});
Console.WriteLine($"결과: {t.Result}");

손쉬운 병렬 처리를 가능케 하는 Parallel 클래스

Parallel.ForParallel.ForEach를 통해 반복 작업을 병렬로 처리할 수 있습니다.

Parallel.For(0, 5, i =>
{
    Console.WriteLine($"인덱스 {i} 처리 중 (스레드 {Thread.CurrentThread.ManagedThreadId})");
});

async 한정자와 await 연산자로 만드는 비동기 코드

async/await를 통해 비동기 흐름을 명시적으로 표현할 수 있습니다.

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        string result = await DownloadContentAsync();
        Console.WriteLine(result);
    }

    static async Task<string> DownloadContentAsync()
    {
        using (HttpClient client = new HttpClient())
        {
            return await client.GetStringAsync("https://example.com");
        }
    }
}