C# Thread 사용방법 정리
안녕하세요.
C#에서 Thread는 여러 작업을 동시에 수행할 수 있는 멀티태스킹의 기초를 제공합니다. 스레드는 프로그램 내에서 독립적으로 실행되는 경량 프로세스입니다. 여러 스레드를 사용하면 CPU의 여러 코어를 활용하여 프로그램의 성능을 향상시키거나, 사용자 인터페이스가 응답성을 유지하도록 할 수 있습니다.
# 기본적인 스레드 생성 및 시작
C#에서 Thread 클래스를 사용하여 새로운 스레드를 만들고 시작할 수 있습니다.
using System;
using System.Threading;
class Program
{
static void Main()
{
// 스레드가 실행할 메서드를 지정하여 스레드 생성
Thread myThread = new Thread(MyThreadMethod);
// 스레드 시작
myThread.Start();
// 메인 스레드의 작업
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Main Thread: " + i);
Thread.Sleep(100); // 100ms 동안 대기
}
}
// 새 스레드에서 실행될 메서드
static void MyThreadMethod()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("MyThreadMethod: " + i);
Thread.Sleep(100); // 100ms 동안 대기
}
}
}
결과:
MyThreadMethod: 0
Main Thread: 0
MyThreadMethod: 1
Main Thread: 1
MyThreadMethod: 2
Main Thread: 2
MyThreadMethod: 3
Main Thread: 3
MyThreadMethod: 4
Main Thread: 4
- Thread myThread = new Thread(MyThreadMethod);:
- MyThreadMethod라는 메서드를 실행할 새 스레드를 만듭니다.
- myThread.Start();:
- 새 스레드를 시작합니다. 이 메서드를 호출하면 MyThreadMethod가 독립적으로 실행됩니다.
- Thread.Sleep(100);:
- 스레드를 지정된 시간(밀리초) 동안 일시 중지시킵니다. 여기서는 100ms 동안 스레드가 대기합니다.
# 스레드의 상태 관리
스레드의 상태를 관리할 수 있는 여러 메서드가 제공됩니다.
- Join(): 현재 스레드가 완료될 때까지 호출한 스레드가 대기합니다.
- IsAlive: 스레드가 아직 실행 중인지를 나타냅니다.
- Abort(): 스레드의 실행을 강제 종료합니다. (이 메서드는 권장되지 않으며, 예외를 발생시킬 수 있습니다.)
using System;
using System.Threading;
class Program
{
static void Main()
{
Thread myThread = new Thread(MyThreadMethod);
myThread.Start();
// 스레드가 끝날 때까지 대기
myThread.Join();
Console.WriteLine("MyThread has completed.");
Console.WriteLine("Main Thread Ends.");
}
static void MyThreadMethod()
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine("MyThreadMethod: " + i);
Thread.Sleep(500);
}
}
}
- myThread.Join();:
- 메인 스레드는 myThread가 완료될 때까지 대기합니다. MyThreadMethod가 실행된 후 "MyThread has completed." 메시지가 출력됩니다.
# 멀티스레딩의 주의점: 공유 자원 동기화
여러 스레드가 동일한 자원에 접근할 때, 동기화 문제(경쟁 조건)가 발생할 수 있습니다. 이를 방지하기 위해 lock 문을 사용하여 자원 접근을 보호할 수 있습니다.
using System;
using System.Threading;
class Program
{
static object lockObject = new object();
static int counter = 0;
static void Main()
{
Thread t1 = new Thread(Increment);
Thread t2 = new Thread(Increment);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine("Final counter: " + counter);
}
static void Increment()
{
for (int i = 0; i < 100000; i++)
{
lock (lockObject)
{
counter++;
}
}
}
}
- lock (lockObject):
- counter 변수에 접근할 때 다른 스레드가 동시에 접근하지 못하도록 잠금을 설정합니다. 이를 통해 경쟁 조건을 방지합니다.
- 경쟁 조건:
- 여러 스레드가 동시에 counter 변수에 접근하면 예기치 않은 결과가 발생할 수 있습니다. lock 문을 사용하여 이를 방지합니다.
# 스레드 풀 사용
스레드를 직접 관리하는 대신, ThreadPool을 사용하여 간단하게 스레드를 관리할 수 있습니다. ThreadPool은 미리 준비된 스레드를 사용하여 작업을 처리합니다.
using System;
using System.Threading;
class Program
{
static void Main()
{
// 스레드 풀에 작업 큐잉
ThreadPool.QueueUserWorkItem(ThreadPoolMethod);
Console.WriteLine("Main Thread Ends.");
Thread.Sleep(1000); // 잠시 대기하여 스레드 풀의 작업이 완료될 시간 제공
}
static void ThreadPoolMethod(object state)
{
Console.WriteLine("ThreadPool Method Executing...");
}
}
- ThreadPool.QueueUserWorkItem:
- 스레드 풀에 작업을 큐잉합니다. ThreadPoolMethod가 스레드 풀에서 실행됩니다.
# 결론
C#에서 스레드는 복잡한 프로그램에서 병렬 처리를 수행하고 응답성을 유지하는 데 중요한 도구입니다. 하지만 잘못된 스레드 사용은 동기화 문제나 예기치 않은 버그를 초래할 수 있으므로 신중한 설계가 필요합니다. Thread 클래스나 ThreadPool을 사용하여 스레드를 적절하게 관리하는 것이 중요하며, 필요한 경우 lock을 사용하여 공유 자원을 보호해야 합니다.
(chat gpt 참고)