3.4 Controlling Process and Thread Priorities

Threads are scheduled for CPU time according to their priority, as described above in the section on scheduling. The priority of each thread is determined by:

The priority class of its process (Idle, Normal, or High)

The base priority level of the thread within the class of its process (Lowest, Below Normal, Normal, Above Normal, Highest)

The dynamic priority boost, if any, that the system has applied to the thread's priority

Your application can control the priority of its processes and threads as follows:

It can specify the priority class of a child process when it uses CreateProcess. If not specified, the priority class defaults to Normal.

It can use SetPriorityClass to change the priority class of any process for which it has a handle. This affects the priority of all threads of the process, the relative priority of the threads remains the same.

It can use SetThreadPriority to change the priority level of any thread for which it has a handle. This sets the thread's base priority to one of the five levels within the priority class of its process. All threads are started at the Normal priority for their priority class.

Use GetPriorityClass to determine the current priority class of a process, and GetThreadPriority to determine the level within its priority class of a thread.

The priority class controls the scheduling of all the threads of a process. The three classes are intended to be used as follows:

Priority Description

Idle The process should only be run when the system is idle. It will always be pre-empted by any process running in a higher priority class. An example of an idle process would be a screen saver application which runs only when there are no runnable normal or high priority tasks.
Normal The process is a normal application with no special scheduling needs. All processes by default are created and run in this priority classification. Normal runnable processes will always pre-empt an Idle process. This means that in the screen saver example, if the screen saver were started, but you were doing a big compile, the screen saver would only get scheduled when the compile was blocked, and that the screen saver would get pre-empted whenever the compile became runnable.
High The process is a high priority application with special scheduling needs that must be addressed in order for it to run correctly. An example of this would be the Windows task manager, which spends most of its time waiting idle, but when the user interacts its performance has to be absolutely crisp and unaffected by other CPU intensive applications. When the Ctrl-Esc hot key sequence occurs, the task manager needs to spring to life and compute the set of top level windows. Once this is done, it displays its task list and waits for input. People expect the task manager to come up very quickly even when there is a ton of activity on a pegged out system. By making the task manager a high priority task, the desired affect is easily achieved.

Using the high priority class should be done with extreme care. If a thread executes at the highest priority level for extended periods, other threads in the system will be starved for CPU time. Or if several threads are set at high priority at the same time, the effects will be neutralized. The high priority class should be reserved for threads that must respond to time critical events. If your application has a task that requires the high priority class while most of its functions are normal priority, you could use SetPriorityClass to temporarily raise the priority class and then reduce it once the time critical task has been completed. Another strategy would be to create a high priority process that remains blocked most of the time, awakening only when the critical task is needed . The important point is that a thread should be high priority and executable only for a brief period while it has time critical work to perform.

Having selected a priority class for a multithreaded process, you may want to use SetThreadPriority to adjust the relative priority of its threads. A typical strategy would be to use a higher priority level for the application's input thread to ensure responsiveness to the user. Other threads, particularly those that are CPU intensive, can be set to a lower relative priority to ensure that they can be preempted when necessary. However, if you have a higher priority thread waiting for a lower priority thread to complete some task, be sure to block the execution of the waiting thread (by using a wait function, critical section, or sleep) rather than having it spin in a while loop. Otherwise, the process will deadlock since the lower priority thread will never get scheduled.