The Windows Processes and Threads 5






Thread Ordering Service


The thread ordering service controls the execution of one or more client threads. It ensures that each client thread runs once during the specified period and in relative order.

Windows Server 2003 and Windows XP/2000:  The thread ordering service is not available. Each client thread belongs to a thread ordering group. The parent thread creates one or more thread ordering groups by calling the AvRtCreateThreadOrderingGroup() function. The parent thread uses this function to specify the period for the thread ordering group and a time-out interval. Additional client threads call the AvRtJoinThreadOrderingGroup() function to join an existing thread ordering group. These threads indicate whether they are to be a predecessor or successor to the parent thread in the execution order. Each client thread is expected to complete a certain amount of processing each period. All threads within the group should complete their execution within the period plus the time-out interval. The threads of a thread ordering group enclose their processing code within a loop that is controlled by the AvRtWaitOnThreadOrderingGroup() function. First, the predecessor threads are executed one at a time in the order that they joined the group, while the parent and successor threads are blocked on their calls to AvRtWaitOnThreadOrderingGroup(). When each predecessor thread is finished with its processing, control of execution returns to the top of its processing loop and the thread calls AvRtWaitOnThreadOrderingGroup() again to block until its next turn. After all predecessor threads have called this function, the thread ordering service can schedule the parent thread. Finally, when the parent thread finishes its processing and calls AvRtWaitOnThreadOrderingGroup() again, the thread ordering service can schedule the successor threads one at a time in the order that they joined the group. If all threads complete their execution before a period ends, all threads wait until the remainder of the period elapses before any are executed again.

When the client need no longer run as part of the thread ordering group, it calls the AvRtLeaveThreadOrderingGroup() function to remove itself from the group. Note that the parent thread should not remove itself from a thread ordering group. If a thread does not complete its execution before the period plus the time-out interval elapses, then it is deleted from the group. The parent thread calls the AvRtDeleteThreadOrderingGroup() function to delete the thread ordering group. The thread ordering group is also destroyed if the parent thread does not complete its execution before the period plus the time-out interval elapses. When the thread ordering group is destroyed, any calls to AvRtWaitOnThreadOrderingGroup() from threads of that group fail or time out.


Multimedia Class Scheduler Service


The Multimedia Class Scheduler service (MMCSS) enables multimedia applications to ensure that their time-sensitive processing receives prioritized access to CPU resources. This service enables multimedia applications to utilize as much of the CPU as possible without denying CPU resources to lower-priority applications. MMCSS uses information stored in the registry to identify supported tasks and determine the relative priority of threads performing these tasks. Each thread that is performing work related to a particular task calls the AvSetMmMaxThreadCharacteristics() or AvSetMmThreadCharacteristics() function to inform MMCSS that it is working on that task.

MMCSS is not available in Windows Server 2003 and Windows XP/2000


Registry Settings


The MMCSS settings are stored in the following registry key:


HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Multimedia\SystemProfile


This key contains a REG_DWORD value named SystemResponsiveness that determines the percentage of CPU resources that should be guaranteed to low-priority tasks. For example, if this value is 20, then 20% of CPU resources are reserved for low-priority tasks. Note that values that are not evenly divisible by 10 are rounded up to the nearest multiple of 10. A value of 0 is also treated as 10. The key also contains a subkey named Tasks that contains the list of tasks. By default, Windows supports the following tasks:


  1. Audio
  2. Capture
  3. Distribution
  4. Games
  5. Playback
  6. Pro Audio
  7. Window Manager


OEMs can add additional tasks as required. Each task key contains the following set of values that represent characteristics to be applied to threads that are associated with the task.




Possible values



A bit mask that indicates the processor affinity. Both 0x00 and 0xFFFFFFFF indicate that processor affinity is not used.

Background Only


Indicates whether this is a background task (no user interface). The threads of a background task do not change because of a change in window focus. This value can be set to True or False.



The background priority. The range of values is 1-8.

Clock Rate


The maximum guaranteed clock rate the system uses if a thread joins this task, in 100-nanosecond intervals.

GPU Priority


The GPU priority. The range of values is 0-31. This priority is not yet used.



The task priority. The range of values is 1 (low) to 8 (high).

For tasks with a Scheduling Category of High, this value is always treated as 2.

Scheduling Category


The scheduling category. This value can be set to High, Medium, or Low.

SFIO Priority


The scheduled I/O priority. This value is reflected by all IRPs issued by threads joined to this task. This value can be set to Idle, Low, Normal, or High. Critical priority is reserved for the memory manager.


Thread Priorities


The MMCSS boosts the priority of threads that are working on high-priority multimedia tasks. MMCSS determines the priority of a thread using the following factors:


  1. The base priority of the task
  2. The Priority parameter of the AvSetMmThreadPriority() function
  3. Whether the application is in the foreground
  4. How much CPU time is being consumed by the threads in each category


MMCSS sets the priority of client threads depending on their scheduling category.







These threads run at a thread priority that is only lower than certain system-level tasks. This category is designed for pro audio and can theoretically use as much of the CPU resource as required.



These threads are part of the application that is in the foreground.



This category contains the remainder of the threads. They are guaranteed a minimum percentage of the CPU resources if required.


These threads have used their quota of CPU resource. They can continue to run if no low-priority threads are ready to run.


Processor Groups


The 64-bit versions of Windows 7 and Windows Server 2008 R2 support more than 64 logical processors on a single computer. This functionality is not available on 32-bit versions of Windows. Systems with more than one processor or systems with processors that have multiple cores provide the operating system with multiple logical processors. A logical processor is one logical computing engine from the perspective of the operating system, application or driver. A core is one processor unit, which can consist of one or more logical processors. A physical processor can consist of one or more cores. A physical processor is the same as a processor package, a socket, or a CPU. Support for systems that have more than 64 logical processors is based on the concept of a processor group, which is a static set of up to 64 logical processors that is treated as a single scheduling entity. Processor groups are numbered starting with 0. Systems with fewer than 64 logical processors always have a single group, Group 0. Processor groups are not supported in Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP/2000.

When the system starts, the operating system creates processor groups and assigns logical processors to the groups. If the system is capable of hot-adding processors, the operating system allows space in groups for processors that might arrive while the system is running. The operating system minimizes the number of groups in a system. For example, a system with 128 logical processors would have two processor groups with 64 processors in each group, not four groups with 32 logical processors in each group. For better performance, the operating system takes physical locality into account when assigning logical processors to groups. All of the logical processors in a core, and all of the cores in a physical processor, are assigned to the same group, if possible. Physical processors that are physically close to one another are assigned to the same group. A NUMA node is assigned to a single group unless the capacity of the node exceeds the maximum group size. On systems with 64 or fewer processors, existing applications will operate correctly without modification. Applications that do not call any functions that use processor affinity masks or processor numbers will operate correctly on all systems, regardless of the number of processors. To operate correctly on systems with more than 64 logical processors, the following kinds of applications might require modification:


  1. Applications that manage, maintain, or display per-processor information for the entire system must be modified to support more than 64 logical processors. An example of such an application is Windows Task Manager, which displays the workload of each processor in the system.
  2. Applications for which performance is critical and that can scale efficiently beyond 64 logical processors must be modified to run on such systems. For example, database applications might benefit from modifications.
  3. If an application uses a DLL that has per-processor data structures, and the DLL has not been modified to support more than 64 logical processors, all threads in the application that call functions exported by the DLL must be assigned to the same group.


By default, an application is constrained to a single group, which should provide ample processing capability for the typical application. The operating system initially assigns each process to a single group in a round-robin manner across the groups in the system. A process begins its execution assigned to one group. The first thread of a process initially runs in the group to which the process is assigned. Each newly created thread is assigned to the same group as the thread that created it. An application that requires the use of multiple groups so that it can run on more than 64 processors must explicitly determine where to run its threads and is responsible for setting the threads' processor affinities to the desired groups. The INHERIT_PARENT_AFFINITY flag can be used to specify a parent process (which can be different than the current process) from which to generate the affinity for a new process. If the process is running in a single group, it can read and modify its affinity using GetProcessAffinityMask() and SetProcessAffinityMask() while remaining in the same group; if the process affinity is modified, the new affinity is applied to its threads.

A thread's affinity can be specified at creation using the PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY extended attribute with the CreateRemoteThreadEx() function. After the thread is created, its affinity can be changed by calling SetThreadAffinityMask() or SetThreadGroupAffinity(). If a thread is assigned to a different group than the process, the process's affinity is updated to include the thread's affinity and the process becomes a multi-group process. Further affinity changes must be made for individual threads; a multi-group process's affinity cannot be modified using SetProcessAffinityMask(). The GetProcessGroupAffinity() function retrieves the set of groups to which a process and its threads are assigned. A logical processor is identified by its group number and its group-relative processor number. This is represented by a PROCESSOR_NUMBER structure. Numeric processor numbers used by legacy functions are group-relative.


Multiple Threads


A thread is the entity within a process that can be scheduled for execution. All threads of a process share its virtual address space and system resources. Each process is started with a single thread, but can create additional threads from any of its threads.




< Processes & Threads 4 | Win32 Process & Thread Programming | Win32 Programming | Processes & Threads 6 >