다음을 통해 공유


스레드 스케줄링

모든 스레드에는 할당된 스레드 우선 순위가 있습니다. 공용 언어 런타임 내에서 생성된 스레드에는 초기에 ThreadPriority.Normal의 우선 순위가 할당됩니다. 런타임 외부에서 생성된 스레드는 관리되는 환경에 들어가기 전의 우선 순위를 유지합니다. Thread.Priority 속성이 있는 스레드의 우선 순위를 가져오거나 설정할 수 있습니다.

스레드는 우선 순위에 따라 실행되도록 예약됩니다. 스레드가 런타임 내에서 실행 중인 경우에도 모든 스레드에는 운영 체제에 의해 프로세서 시간 조각이 할당됩니다. 스레드가 실행되는 순서를 확인하는 데 사용되는 예약 알고리즘의 세부 정보는 각 운영 체제에 따라 다릅니다. 일부 운영 체제에서는 실행할 수 있는 스레드 중 우선 순위가 가장 높은 스레드가 항상 첫 번째로 실행되도록 예약됩니다. 우선 순위가 동일한 여러 스레드가 모두 사용 가능한 경우 스케줄러는 해당 우선 순위에 있는 스레드를 순환하여 각 스레드에 실행할 고정 시간 조각을 제공합니다. 우선 순위가 더 높은 스레드를 실행할 수 있는 경우에는 우선 순위가 더 낮은 스레드는 실행되지 않습니다. 지정된 우선 순위에 실행 가능한 스레드가 더 이상 없는 경우 스케줄러는 다음으로 낮은 우선 순위로 이동하고 해당 우선 순위의 스레드를 실행하도록 예약합니다. 우선 순위가 더 높은 스레드가 실행 가능해지면 우선 순위가 더 낮은 스레드가 대체되고 우선 순위가 더 높은 스레드가 다시 한번 실행될 수 있습니다. 무엇보다 이 운영 체제에서는 애플리케이션의 사용자 인터페이스가 포그라운드와 백그라운드 사이에서 이동될 때 스레드 우선 순위를 동적으로 조정할 수 있습니다. 다른 운영 체제에서는 다른 예약 알고리즘을 사용하도록 선택할 수 있습니다.

예시

다음은 마지막 5개가 가장 높은 우선 순위 수준에 있는 Thread.Priority 열거형의 5개 우선 순위 수준 모두에서 9개 스레드를 실행하는 예입니다. 또한 이 컨텍스트에서 스레드 초기화 및 우선 순위 지정 순서가 후속 코드나 프로세스 실행 시작 순서에 항상 반영되지 않을 수 있음을 보여 주는 이전 문서의 콜백 지원이 있습니다. 즉, 여기서는 코드 실행의 병렬 특성과 모든 스레드에 대해 운영 체제에 의해 할당된 프로세서 시간 조각의 데모를 볼 수 있습니다. 이는 스레드가 실행되는 환경의 영향과 제어를 강조 표시합니다. 즉, 우선 순위가 가장 높은 스레드가 실제로 실행 우선 순위를 받는다는 것을 확실히 알 수 있습니다.

다음 코드는 각 실행에서 임의의 결과를 생성합니다. 그러나 코드를 여러 번 실행하고 출력을 분석한 후에 실행되는 우선 순위의 공통 시퀀스 패턴을 관찰할 수 있습니다.

namespace snippets;

public class SchedulingThreads
{
    public void RunMultipleThreadsOnDifferentPriorities()
    {
        var threadsList = new List<Thread>(9);

        // Initialize 9 threads. 5 with Highest priority, and the first 4 from Lowest to Normal range.
        for (int i = 0; i < 9; i++)
        {
            var thread = new Thread(() => { new ThreadWithCallback(Callback).Process(); });

            if (i > 3)
                thread.Priority = ThreadPriority.Highest;
            else
                thread.Priority = (ThreadPriority)i;

            threadsList.Add(thread);
        }

        threadsList.ForEach(thread => thread.Start());
    }

    public void Callback(ThreadPriority threadPriority)
    {
        Console.WriteLine($"Callback in {threadPriority} priority. \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}.");
    }

    public class ThreadWithCallback
    {
        public ThreadWithCallback(Action<ThreadPriority> callback)
        {
            this.callback = callback;
        }

        public Action<ThreadPriority> callback;

        public void Process()
        {
            Console.WriteLine($"Entered process in {Thread.CurrentThread.Priority} priority.  \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}.");
            Thread.Sleep(1000);
            Console.WriteLine($"Finished process in {Thread.CurrentThread.Priority} priority. \t\t ThreadId: {Thread.CurrentThread.ManagedThreadId}.");

            if (callback != null)
            {
                callback(Thread.CurrentThread.Priority);
            }
        }
    }

    // The example displays the output like the following:
    //      Entered process in Highest priority.             ThreadId: 9.
    //      Entered process in Highest priority.             ThreadId: 12.
    //      Entered process in Normal priority.              ThreadId: 6.
    //      Entered process in BelowNormal priority.         ThreadId: 5.
    //      Entered process in Lowest priority.              ThreadId: 4.
    //      Entered process in AboveNormal priority.         ThreadId: 7.
    //      Entered process in Highest priority.             ThreadId: 11.
    //      Entered process in Highest priority.             ThreadId: 10.
    //      Entered process in Highest priority.             ThreadId: 8.
    //      Finished process in Highest priority.            ThreadId: 9.
    //      Finished process in Highest priority.            ThreadId: 12.
    //      Finished process in Highest priority.            ThreadId: 8.
    //      Finished process in Highest priority.            ThreadId: 10.
    //      Callback in Highest priority.                    ThreadId: 10.
    //      Finished process in AboveNormal priority.        ThreadId: 7.
    //      Callback in AboveNormal priority.                ThreadId: 7.
    //      Finished process in Lowest priority.             ThreadId: 4.
    //      Callback in Lowest priority.                     ThreadId: 4.
    //      Finished process in Normal priority.             ThreadId: 6.
    //      Callback in Highest priority.                    ThreadId: 9.
    //      Callback in Highest priority.                    ThreadId: 8.
    //      Callback in Highest priority.                    ThreadId: 12.
    //      Finished process in Highest priority.            ThreadId: 11.
    //      Callback in Highest priority.                    ThreadId: 11.
    //      Callback in Normal priority.                     ThreadId: 6.
    //      Finished process in BelowNormal priority.        ThreadId: 5.
    //      Callback in BelowNormal priority.                ThreadId: 5.
}

참고 항목