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.
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 Scheduler and CurrentScheduler Classes
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.
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.
Creating a Scheduler Instance
There are these three ways to create a
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
Schedulerobject that uses a specific policy and associates that scheduler with the current context.
The concurrency::Scheduler::Create method creates a
Schedulerobject 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.
Managing the Lifetime of a Scheduler Instance
The runtime uses a reference-counting mechanism to control the lifetime of
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
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
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|
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.
Because the runtime does not destroy a
Scheduler object before all tasks have finished, you can use the concurrency::Scheduler::RegisterShutdownEvent method or the concurrency::CurrentScheduler::RegisterShutdownEvent method to receive a notification when a
Scheduler object is destroyed. This is useful when you must wait for every task that is scheduled by a
Scheduler object to finish.
Methods and Features
This section summarizes the important methods of the
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
|Get||Retrieves a pointer to the
|Detach||Detaches the current scheduler from the current context and sets the previous one as the current scheduler.|
|RegisterShutdownEvent||Registers an event that the runtime sets when the current scheduler is destroyed.|
|CreateScheduleGroup||Creates a concurrency::ScheduleGroup object in the current scheduler.|
|ScheduleTask||Adds a lightweight task to the scheduling queue of the current scheduler.|
|GetPolicy||Retrieves a copy of the policy that is associated with the current scheduler.|
The following table shows the important methods that are defined by the
|Reference||Increments the reference counter of the
|Release||Decrements the reference counter of the
|RegisterShutdownEvent||Registers an event that the runtime sets when the
|CreateScheduleGroup||Creates a concurrency::ScheduleGroup object in the
|ScheduleTask||Schedules a lightweight task from the
|GetPolicy||Retrieves a copy of the policy that is associated with the
|SetDefaultSchedulerPolicy||Sets the policy for the runtime to use when it creates the default scheduler.|
|ResetDefaultSchedulerPolicy||Restores the default policy to the one that was active before the call to
For basic examples of how to create and manage a scheduler instance, see How to: Manage a Scheduler Instance.