.NET 프레임워크에는 스레드를 나타내는 클래스로 System.Threading.Thread를 제공합니다.
사용법은
Step 1: Thread의 인스턴스를 생성합니다. 이때 생성자의 매개 변수로 스레드가 실행할 메소드를 넘깁니다.
Step 2: Thread.Start() 메소드를 호출하여 스레드를 시작합니다.
Step 3: Thread.Join() 메소드를 호출하여 스레드가 끝날 때까지 기다립니다.
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
// Step 1: 스레드의 인스턴스를 만들고 매개 변수로 실행할 메서드를 전달합니다
Thread thread = new Thread(new ThreadStart(DoWork));
// Step 2: 스레드가 동작하도록 함(메모리에 적재됨)
thread.Start();
// Step 3: 스레드가 끝날 때까지 기다립니다
thread.Join();
Console.WriteLine("Thread has ended.");
}
static void DoWork()
{
Console.WriteLine("Thread is running.");
Thread.Sleep(5000);
Console.WriteLine("Thread has finished its work.");
}
}
Join() 메소드는 메인 스레드에서 스레드가 빠져나왔다가 다시 메인 스레드로 join 한다고 생각하면 됩니다.
Sleep() 메소드는 다른 스레드도 CPU를 사용할 수 있도록 CPU 점유를 내려놓습니다.(WaitSleepJoin 상태로 들어가게 함)
스레드를 종료시키는 방법 2가지
1. Thread.Abort() 메소드
Abort() 메소드는 goto 문을 사용하는 것만큼이나 금기시되어 있습니다.
왜냐하면, 한 스레드가 어떤 자원을 독점하고자 잠가버린 후 잠금을 풀지 못하고 Abort() 메소드를 호출 당해 갑자기 종료되어 버리면, 그 자원에 접근하고자 하는 다른 스레드들은 들어가지 못하는 상태가 되어 버립니다.
그리고 Abort() 메소드를 사용할 때는 고려해야 할 사항이 있습니다. 그것은 바로 Abort() 메소드를 호출한다고 해서 동작하던 스레드가 즉시 종료된다는 보장이 없습니다.
실행 중이던 스레드에 Abort() 메소드를 호출하면 CLR은 해당 스레드가 실행 중이던 코드에 ThreadAbortException을 호출합니다.
이때, 이 예외를 catch 하는 코드가 있으면 이 예외를 처리한 다음, finally 블록까지 실행한 후에야 해당 스레드가 완전히 종료됩니다.
이 사항을 반드시 고려해야 합니다.
using System;
using System.Threading;
namespace AbortingThread
{
class SideTask
{
int count;
public SideTask(int count)
{
this.count = count;
}
public void KeepAlive()
{
try
{
while (count > 0)
{
Console.WriteLine($"{count--} left");
Thread.Sleep(10);
}
Console.WriteLine("Count : 0");
}
catch (ThreadAbortException e)
{
Console.WriteLine(e);
Thread.ResetAbort();
}
finally
{
Console.WriteLine("Clearing resource...");
}
}
}
class MainApp
{
static void Main(string[] args)
{
SideTask task = new SideTask(100);
Thread t1 = new Thread(new ThreadStart(task.KeepAlive));
t1.IsBackground = false;
Console.WriteLine("Starting thread...");
t1.Start();
Thread.Sleep(100);
Console.WriteLine("Aborting thread...");
t1.Abort();
Console.WriteLine("Wating until thread stops...");
t1.Join();
Console.WriteLine("Finished");
}
}
}
Abort() 쓰지 말라고 하네요 (^∇^*)
2. Thread.Interrupt() 메소드
스레드는 수명이 다해 스스로 종료하는 것이 가장 좋지만, 불가피하게 스레드를 강제로 종료시켜야 하는 경우가 많습니다. Interrupt()는 이 경우 Abort() 보다 조금 더 부드러운 방법을 사용합니다.
바로 스레드가 한참 동작 중일 때(Running)가 아닌 WaitJoinSleep 상태에 들어갔을 때만 ThreadInterruptedException 예외를 던져 스레드를 중지시킵니다.
이런 특징 덕분에 절대로 중단되면 안 되는 작업을 하고 있을 때에는 중단되지 않는다는 보장을 받을 수 있습니다.
using System;
using System.Security.Permissions;
using System.Threading;
namespace InterruptingThread
{
class SideTask
{
int count;
public SideTask(int count)
{
this.count = count;
}
public void KeepAlive()
{
try
{
Console.WriteLine("Running thread isn't gonna be interrupted");
//Sleep()과 유사하게 스레드를 대기하게 하지만
//Sleep()과 달리 WaitSleepJoin 상태가 아닌 Running 상태를 유지하게 함
Thread.SpinWait(10000000);
while (count > 0)
{
Console.WriteLine($"{count--} left");
Console.WriteLine("Entering into WaitJoinSleep State...");
//WaitSleepJoin 상태로 들어감
Thread.Sleep(10);
}
Console.WriteLine("Count : 0");
}
catch (ThreadInterruptedException e)
{
Console.WriteLine(e);
}
finally
{
Console.WriteLine("Clearing resource...");
}
}
}
class MainApp
{
static void Main(string[] args)
{
SideTask task = new SideTask(100);
Thread t1 = new Thread(new ThreadStart(task.KeepAlive));
t1.IsBackground = false;
Console.WriteLine("Starting thread...");
t1.Start();
Thread.Sleep(100);
Console.WriteLine("Interrupting thread...");
t1.Interrupt();
Console.WriteLine("Wating until thread stops...");
t1.Join();
Console.WriteLine("Finished");
}
}
}
'C# 프로그래밍' 카테고리의 다른 글
[C#] 스레드 사용법(2) (0) | 2023.03.14 |
---|---|
프로세스와 스레드에 대한 이론 정리글(2) (0) | 2023.03.13 |
프로세스와 스레드에 대한 이론 정리글(1) (feat. chat gpt) (0) | 2023.03.09 |
[C#] 직렬화 (0) | 2023.03.07 |
"=>" 연산자가 람다식 말고 쓰이는 곳 "식 본문 멤버" (0) | 2023.03.06 |