ThreadPool 클래스와 Task 클래스를 이용하여 쓰레드를 생성해보자.

쓰레드의 수의 제한이 없다보면 CPU와 쓰레드를 연결하는데 지나치게 많은 시간이 소모된다.

ThreadPool 클래스의 경우, 작업을 하는 쓰레드의 개수가 정해져있다. 따라서 작업이 많을 시 대기 시간이 필연적으로 발생한다.

아래 코드를 살펴보자.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ServerCore
{
    class Program
    {

        static void MainThread(object state)
        {

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Hello World");
            }
        }

        static void Main(string[] args)
        {
            ThreadPool.SetMinThreads(1, 1); // 쓰레드 개수를 최소 1개 
            ThreadPool.SetMaxThreads(5, 5); // 최대 5개로 설정한다. 
	    
            for (int i = 0; i < 5; i++) // 5개의 쓰레드를 모두 사용 
            {
                ThreadPool.QueueUserWorkItem((obj) => { while (true) { } });

            } 

            ThreadPool.QueueUserWorkItem(MainThread); // 다른 쓰레드에 MainThread 함수를 실행하도록 요청

            while (true) { } // Background Thread가 완료되기 전에 application이 종료되지 않게 한다. 

        }
    }
}

위 코드의 결과 아무런 동작이 일어나지 않는다.
for 문에서 이미 5개의 쓰레드가 전부 while문을 반복하기에
MainThread를 실행시킬 여분의 쓰레드가 남아있지 않았다.

아래와 같이 코드를 수정해보자.

for(int i=0;i<4;i++) // 4개의 쓰레드를 사용하도록 변경 
{
	ThreadPool.QueueUserWorkItem((obj) => 
    { while (true) { } });
}

1개의 남은 쓰레드로 MainThread 함수가 실행되는 것을 확인할 수 있다.

CPU에 부하가 걸리는 것을 막을 수 있겠지만 처리방식이 굉장히 비효율적이다. 쓰레드가 부족하면 스케줄러 자동으로 여분의 쓰레드를 요청할 수 있는 방법이 없을까?

이 문제를 해결해주는 것이 바로 Task 클래스이다.

for (int i = 0; i < 5; i++)
{
Task t = new Task(delegate () { while (true) { } }
, TaskCreationOptions.LongRunning); 
// ThreadPool에서 뽑아 쓰는 것이 아닌 스케줄러에 요청한 별도의 Thread로 작업한다. 

t.Start();
}

위와 같이 코드를 수정한다.

Task 인스턴스를 생성할 때 TaskCreationOptions.LongRunning 을 인자로 넘겨주면, 스케줄러에서 부족한 쓰레드를 요청하여 작업할 수 있다.


위 사진과 같이, MainThread 함수가 원할히 실행됨을 확인할 수 있다.

profile
POSTECH EE 18 / Living every minute of LIFE

0개의 댓글