ThreadPool을 이용할 때, ThreadPool에 위임한 백그라운드 스레드들의 작업이 모두 끝난지 어떻게 확인할 수 있을까?
MSDN에서 읽은 자료가 아니라 확신은 들지 않지만 한 블로그의 포스트를 참조하였다.

 Thread 클래스를 이용하여 직접 스레드를 생성하였을 때, 스레드의 작업 완료를 기다리기 위해 Join 메소드를 사용할 수 있다. 하지만 ThreadPool 클래스는 Join 메소드를 제공하지 않는다. ThreadPool 의 정적 메소드인 GetMaxThreads, GetAvailableThreads 메소드를 사용하여 ThreadPool의 모든 스레드가 종료될 때 까지 기다릴 수 있다. 참조한 포스트에서는 이런 방법이 충분하지 않다면 직접 ThreadPool을 구현 하라고 한다.

GetMaxThreads
스레드풀에서 허용되는 최대 작업자 스레드 수를 구한다.

GetAvailableThreads
조사하는 시점에, 스레드풀에서 시작될 수 있는 추가 작업자 스레드 수 즉, 사용 가능한 스레드 수를 구한다.

참조한 코드를 보면,

        public static void Main(string[] args)
        {
            for (int i = 0; i < 2000; i++)
            {
                Thread.Sleep(50);
                ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), i);
            }

            Console.WriteLine("Main Thread waiting to complete...");

            bool isWorking = true;
            int workerThreads = 0;
            int completionPortThread = 0;
            int maxWorkerThreads = 0;
            int maxCompletionPortThreads = 0;

            ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads);

            while (isWorking)
            {
                ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThread);

                if (workerThreads == maxWorkerThreads)
                    isWorking = false;
                else
                    Thread.Sleep(500);
            }

            Console.WriteLine("Main Thread completing...");
            Console.ReadKey();
        }


        /// <summary>
        /// 스레드에서의 임의 작업, Sleep 사용
        /// </summary>
        private static void ThreadProc(object stateInfo)
        {
            Console.WriteLine("Thread {0} running...", stateInfo);
            Thread.Sleep(1000);
        }


1. QueueUserWorkItem, Sleep
스레드풀에 QueueUserWorkItem으로 작업을 넣을 때, Sleep(50) 이 있다. 스레드풀에 많은 작업을 넣을 때, 스레드풀에서 블록되는 경우가 있다. 잠깐의 Sleep을 주거나 다른 방법으로 이 문제를 해결 가능하다.

2. GetMaxThreads, GetAvailableThreads
모든 작업을 스레드풀에 요청한 후, GetMaxThreads 메소드로 스레드풀에서 사용 가능한 최대 스레드 개수를 저장해 둔다. 코드에서는 maxWorkerThreads 변수에 저장. 스레드풀에 사용 가능한 최대 스레드 개수는 CPU 마다 다르다. While 반복문에서 GetAbailableThreads 메소드를 실행하여 현재 스레드풀에서 사용 가능한 상태의 스레드 개수를 구한다. 스레드풀에서 처리할 작업을 모두 마친다면 사용 가능한 스레드수가 스레드풀의 사용 가능한 최대 스레드의 개수와 동일해질 것 이다. 그렇다면 스레드풀의 모든 스레드가 종료되었음을 추측할 수 있다. 코드에서는 if (workerThreads == maxWorkerThreads) 부분이다. 

3. Sleep
스레드풀의 모든 스레드가 종료되었는지 판별하는 while 루프에서 모든 스레드가 종료되지 않았을 때 Sleep을 주었다. 


간 혹 몇개의 작업은 잃어버리는것 같긴한데.. 잘 되는 것 같다.



* 이 방법 말고 다른 방법이 있으면 알려주세요. :)

cf) WaitHandle을 이용한 ThreadPool 스레드 종료 대기에 대하여.
 
Posted by six605
,