본격적으로 코드에서 쓰레드 실습을 해보자.
class Threads
{
static void MainThread()
{
while(true)
Console.WriteLine("Hello Thread");
}
static void Main(string[] args)
{
Thread t = new Thread(MainThread);
//t.IsBackground = true; 기본적으론 false로 되어 있어, 쓰레드가 계속 실행된다.
t.Start();
Console.WriteLine("Hello main");
}
}
쓰레드를 만들려면 실행할 함수를 넣어야하며, Start()를 이용해 시작할 수 있다.
해당 코드를 실행하면, Hello Thread!만 주구장창 나와 프로그램이 끝나지 않을 것이다. 이땐 t.IsBackground를 true로 해주면 메인 함수 종료시 쓰레드도 같이 종료하게끔 할 수 있다.
쓰레드는 개수가 제한이 없고, 간단한 작업을 하는데 쓰레드를 쓴다면 CPU에게 큰 부담이 될 수 있다. 그럴 땐 후술할 ThreadPool를 이용하자.
강의의 비유로 설명하자면, 인력 사무소 같은 느낌. 즉 정해진 인원이 QueueUserWorkItem을 통해 실행되면 그 작업이 끝날 때까지는 다른 일을 할 수 없는 개념. 코드를 통해 살펴보자.
static void MainThread(object _obj)
{
for(int i=0;i<5;i++)
Console.WriteLine("Hello Thread");
}
static void Main(string[] args)
{
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(5, 5);
for(int i = 0; i < 5; i++)
{
ThreadPool.QueueUserWorkItem((obj) => { while(true){} });
}
ThreadPool.QueueUserWorkItem(MainThread);
//최대 인력 5명이 전부 무한루프에 빠져, MainThread 실행이 안된다.
while (true)
{
}
}
본 코드에선 SetMinThreads, SetMaxThreads를 통해 쓰레드의 최소, 최대 개수를 정하였다. 그런데, 최대 인원이 5명인 상황에서 어마어마하게 오래 걸리는 일을 맡긴다음, Hello Thread를 5번 출력하는 일을 준다면 어떻게 될까? 일을 맡길 수 있는 사람이 없으니 해당 쓰레드가 실행될 일은 없을 것이다.(당연히, 무한 루프 일거리를 주는 반복문 코드를 4번 실행하게 한다면, 실행될 것이다.)
이 상황에서 Task를 이용한 코드를 보자.
static void MainThread(object _obj)
{
for(int i=0;i<5;i++)
Console.WriteLine("Hello Thread");
}
static void Main(string[] args)
{
//Task도 ThreadPool 넣어 관리
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(5, 5);
//직원이 할 일감을 정의
for (int i = 0; i < 5; i++)
{
//TaskCreationOptions.LongRunning을 이용하면 별도로 관리할 수 있다.
Task t = new Task(() => { while (true) { } }, TaskCreationOptions.LongRunning);
t.Start();
}
ThreadPool.QueueUserWorkItem(MainThread);
while (true)
{
}
}
해당 코드를 실행한다면 의도한 대로 Hello Thread가 5번 출력될 것이다. Task에서의 TaskCreationOptions.LongRunning을 이용하여 별도의 쓰레드를 추가로 요청하였기 때문이다. 어떻게 보면 Task는 Thread와 ThreadPool의 장점만 취합한 친구라고 보면 될 듯싶다.