This document describes the role of scheduler instances in the Concurrency Runtime and how to use the concurrency::Scheduler and concurrency::CurrentScheduler classes to create and manage scheduler instances. Scheduler instances are useful when you want to associate explicit scheduling policies with specific types of workloads. For example, you can create one scheduler instance to run some tasks at an elevated thread priority and use the default scheduler to run other tasks at the normal thread priority.
Tip
The Concurrency Runtime provides a default scheduler, and therefore you are not required to create one in your application. Because the Task Scheduler helps you fine-tune the performance of your applications, we recommend that you start with the Parallel Patterns Library (PPL) or the Asynchronous Agents Library if you are new to the Concurrency Runtime.
The Task Scheduler enables applications to use one or more scheduler instances to schedule work. The concurrency::Scheduler class represents a scheduler instance and encapsulates the functionality that is related to scheduling tasks.
A thread that is attached to a scheduler is known as an execution context, or just context. One scheduler can be active on the current context at any time. The active scheduler is also known as the current scheduler. The Concurrency Runtime uses the concurrency::CurrentScheduler class to provide access to the current scheduler. The current scheduler for one context can differ from the current scheduler for another context. The runtime does not provide a process-level representation of the current scheduler.
Typically, the CurrentScheduler class is used to access the current scheduler. The Scheduler class is useful when you need to manage a scheduler that is not the current one.
The following sections describe how to create and manage a scheduler instance. For a complete example that illustrates these tasks, see How to: Manage a Scheduler Instance.
There are these three ways to create a Scheduler object:
If no scheduler exists, the runtime creates a default scheduler for you when you use runtime functionality, for example, a parallel algorithm, to perform work. The default scheduler becomes the current scheduler for the context that initiates the parallel work.
The concurrency::CurrentScheduler::Create method creates a Scheduler object that uses a specific policy and associates that scheduler with the current context.
The concurrency::Scheduler::Create method creates a Scheduler object that uses a specific policy, but does not associate it with the current context.
Allowing the runtime to create a default scheduler enables all concurrent tasks to share the same scheduler. Typically, the functionality that is provided by the Parallel Patterns Library (PPL) or the Asynchronous Agents Library is used to perform parallel work. Therefore, you do not have to work directly with the scheduler to control its policy or lifetime. When you use the PPL or the Agents Library, the runtime creates the default scheduler if it does not exist and makes it the current scheduler for each context. When you create a scheduler and set it as the current scheduler, then the runtime uses that scheduler to schedule tasks. Create additional scheduler instances only when you require a specific scheduling policy. For more information about the policies that are associated with a scheduler, see Scheduler Policies.
The runtime uses a reference-counting mechanism to control the lifetime of Scheduler objects.
When you use the CurrentScheduler::Create method or the Scheduler::Create method to create a Scheduler object, the runtime sets the initial reference count of that scheduler to one. The runtime increments the reference count when you call the concurrency::Scheduler::Attach method. The Scheduler::Attach method associates the Scheduler object together with the current context. This makes it the current scheduler. When you call the CurrentScheduler::Create method, the runtime both creates a Scheduler object and attaches it to the current context (and sets the reference count to one). You can also use the concurrency::Scheduler::Reference method to increment the reference count of a Scheduler object.
The runtime decrements the reference count when you call the concurrency::CurrentScheduler::Detach method to detach the current scheduler, or call the concurrency::Scheduler::Release method. When the reference count reaches zero, the runtime destroys the Scheduler object after all scheduled tasks finish. A running task is allowed to increment the reference count of the current scheduler. Therefore, if the reference count reaches zero and a task increments the reference count, the runtime does not destroy the Scheduler object until the reference count again reaches zero and all tasks finish.
The runtime maintains an internal stack of Scheduler objects for each context. When you call the Scheduler::Attach or CurrentScheduler::Create method, the runtime pushes that Scheduler object onto the stack for the current context. This makes it the current scheduler. When you call CurrentScheduler::Detach, the runtime pops the current scheduler from the stack for current context and sets the previous one as the current scheduler.
The runtime provides several ways to manage the lifetime of a scheduler instance. The following table shows the appropriate method that releases or detaches the scheduler from the current context for each method that creates or attaches a scheduler to the current context.
Create or attach method
Release or detach method
CurrentScheduler::Create
CurrentScheduler::Detach
Scheduler::Create
Scheduler::Release
Scheduler::Attach
CurrentScheduler::Detach
Scheduler::Reference
Scheduler::Release
Calling the inappropriate release or detach method produces unspecified behavior in the runtime.
When you use functionality, for example, the PPL, that causes the runtime to create the default scheduler for you, do not release or detach this scheduler. The runtime manages the lifetime of any scheduler that it creates.
This section summarizes the important methods of the CurrentScheduler and Scheduler classes.
Think of the CurrentScheduler class as a helper for creating a scheduler for use on the current context. The Scheduler class lets you control a scheduler that belongs to another context.
The following table shows the important methods that are defined by the CurrentScheduler class.
Retrieves a pointer to the Scheduler object that is associated with the current context. This method does not increment the reference count of the Scheduler object.
Restores the default policy to the one that was active before the call to SetDefaultSchedulerPolicy. If the default scheduler is created after this call, the runtime uses default policy settings to create the scheduler.
Azure HPC is a purpose-built cloud capability for HPC & AI workload, using leading-edge processors and HPC-class InfiniBand interconnect, to deliver the best application performance, scalability, and value. Azure HPC enables users to unlock innovation, productivity, and business agility, through a highly available range of HPC & AI technologies that can be dynamically allocated as your business and technical needs change. This learning path is a series of modules that help you get started on Azure HPC - you