/*** * ==++== * * Copyright (c) Microsoft Corporation. All rights reserved. * * ==--== * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * concrtrm.h * * Main public header file for ConcRT's Resource Manager. This is the only header file a client * must include to build atop the resource manager. * * The core runtime, the Agents and Message Blocks Library, and the Parallel Patterns Library (PPL) * are defined in different header files. * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #pragma once #include #if !(defined (_M_X64) || defined (_M_IX86) || defined (_M_ARM)) #error ERROR: Concurrency Runtime is supported only on X64, X86 and ARM architectures. #endif /* !(defined (_M_X64) || defined (_M_IX86) || defined (_M_ARM)) */ #if defined (_M_CEE) #error ERROR: Concurrency Runtime is not supported when compiling /clr. #endif /* defined (_M_CEE) */ #ifndef __cplusplus #error ERROR: Concurrency Runtime is supported only for C++. #endif /* __cplusplus */ #pragma pack(push,_CRT_PACKING) /// /// The Concurrency namespace provides classes and functions that give you access to the Concurrency Runtime, /// a concurrent programming framework for C++. For more information, see . /// /**/ namespace Concurrency { #ifdef _CRT_USE_WINAPI_FAMILY_DESKTOP_APP // // Forward Declarations: // struct IScheduler; struct IThreadProxy; class SchedulerPolicy; /// /// Used to denote the state a thread proxy is in, when it is executing a cooperative context switch to a different thread /// proxy. /// /// /// A parameter of type SwitchingProxyState is passed in to the method IThreadProxy::SwitchTo to /// instruct the Resource Manager how to treat the thread proxy that is making the call. /// For more information on how this type is used, see IThreadProxy::SwitchTo /// . /// /**/ enum SwitchingProxyState { /// /// Indicates that the calling thread is no longer needed by the scheduler and is being returned to the Resource Manager. The /// context which was being dispatched is no longer able to be utilized by the Resource Manager. /// /**/ Idle, /// /// Indicates that the calling thread is cooperatively blocking and should be exclusively owned by the caller until subsequently /// running again and performing other action. /// /**/ Blocking, /// /// Indicates that the calling thread is nesting a child scheduler and is needed by the caller, in order to attach to a /// different scheduler. /// /**/ Nesting }; /// /// The DispatchState structure is used to transfer state to the IExecutionContext::Dispatch method. It describes /// the circumstances under which the Dispatch method is invoked on an IExecutionContext interface. /// /// /**/ struct DispatchState { /// /// Constructs a new DispatchState object. /// /**/ DispatchState() : m_dispatchStateSize(sizeof(DispatchState)), m_fIsPreviousContextAsynchronouslyBlocked(0), m_reserved(0) { } /// /// Size of this structure, which is used for versioning. /// /**/ unsigned long m_dispatchStateSize; /// /// Tells whether this context has entered the Dispatch method because the previous context asynchronously blocked. /// This is used only on the UMS scheduling context, and is set to the value 0 for all other execution contexts. /// /// /**/ unsigned int m_fIsPreviousContextAsynchronouslyBlocked : 1; /// /// Bits reserved for future information passing. /// /// /**/ unsigned int m_reserved : 31; }; /// /// An interface to an execution context which can run on a given virtual processor and be cooperatively context switched. /// /// /// If you are implementing a custom scheduler that interfaces with the Concurrency Runtime's Resource Manager, you will need /// to implement the IExecutionContext interface. The threads created by the Resource Manager perform work on behalf /// of your scheduler by executing the IExecutionContext::Dispatch method. /// /// /// /**/ struct IExecutionContext { /// /// Returns a unique identifier for the execution context. /// /// /// A unique integer identifier. /// /// /// You should use the method GetExecutionContextId to obtain a unique identifier for the object that implements the /// IExecutionContext interface, before you use the interface as a parameter to methods supplied by the Resource Manager. /// You are expected to return the same identifier when the GetId function is invoked. An identifier obtained from a different /// source could result in undefined behavior. /// /// /**/ virtual unsigned int GetId() const =0; /// /// Returns an interface to the scheduler this execution context belongs to. /// /// /// An IScheduler interface. /// /// /// You are required to initialize the execution context with a valid IScheduler interface before you use it as a parameter to /// methods supplied by the Resource Manager. /// /**/ virtual IScheduler * GetScheduler() =0; /// /// Returns an interface to the thread proxy that is executing this context. /// /// /// An IThreadProxy interface. If the execution context's thread proxy has not been initialized with a call to SetProxy, /// the function must return NULL. /// /// /// The Resource Manager will invoke the SetProxy method on an execution context, with an IThreadProxy interface /// as a parameter, prior to entering the Dispatch method on the on the context. You are expected to store this argument and return it /// on calls to GetProxy(). /// /// /**/ virtual IThreadProxy * GetProxy() =0; /// /// Associates a thread proxy with this execution context. The associated thread proxy invokes this method right before it starts /// executing the context's Dispatch method. /// /// /// An interface to the thread proxy that is about to enter the Dispatch method on this execution context. /// /// /// You are expected to save the parameter and return it on a call to the GetProxy method. /// The Resource Manager guarantees that the thread proxy associated with the execution context will not change while the /// thread proxy is executing the Dispatch method. /// /// /**/ virtual void SetProxy(_Inout_ IThreadProxy * pThreadProxy) =0; /// /// The method that is called when a thread proxy starts executing a particular execution context. This should be the main worker /// routine for your scheduler. /// /// /// A pointer to the state under which this execution context is being dispatched. For more information on dispatch state, see /// DispatchState. /// /**/ virtual void Dispatch(_Inout_ DispatchState * pDispatchState) =0; }; /// /// An abstraction for a thread of execution. Depending on the SchedulerType policy key of the scheduler you create, the Resource /// Manager will grant you a thread proxy that is backed by either a regular Win32 thread or a user-mode schedulable (UMS) thread. /// UMS threads are supported on 64-bit operating systems with version Windows 7 and higher. /// /// /// Thread proxies are coupled to execution contexts represented by the interface IExecutionContext as a means of dispatching work. /// /// /// /// /**/ struct IThreadProxy { /// /// Returns a unique identifier for the thread proxy. /// /// /// A unique integer identifier. /// /**/ virtual unsigned int GetId() const =0; /// /// Performs a cooperative context switch from the currently executing context to a different one. /// /// /// The execution context to cooperatively switch to. /// /// /// Indicates the state of the thread proxy that is executing the switch. The parameter is of type . /// /// /// Use this method to switch from one execution context to another, from the /// IExecutionContext::Dispatch method of the first execution context. /// The method associates the execution context with a thread proxy if it is not already associated /// with one. The ownership of the current thread proxy is determined by the value you specify for the /// argument. /// /// Use the value Idle when you want to return the currently executing thread proxy to the Resource Manager. /// Calling SwitchTo with the parameter set to Idle will cause /// the execution context to start executing on the underlying execution resource. Ownership of /// this thread proxy is transferred to the Resource Manager, and you are expected to return from the execution context's /// Dispatch method soon after SwitchTo returns, in order to complete the transfer. The execution context that the /// thread proxy was dispatching is disassociated from the thread proxy, and the scheduler is free to reuse it or destroy it /// as it sees fit. /// /// Use the value Blocking when you want this thread proxy to enter a blocked state. Calling /// SwitchTo with the parameter set to Blocking will cause the execution context /// to start executing, and block the current thread proxy until it is resumed. The scheduler retains /// ownership of the thread proxy when the thread proxy is in the Blocking state. The blocking thread proxy /// can be resumed by calling the function SwitchTo to switch to this thread proxy's execution context. You can also /// resume the thread proxy, by using its associated context to activate a virtual processor root. For more information on how /// to do this, see IVirtualProcessorRoot::Activate. /// /// Use the value Nesting when you want to temporarily detach this thread proxy from the virtual processor root /// it is running on, and the scheduler it is dispatching work for. Calling SwitchTo with the parameter /// set to Nesting will cause the execution context to start executing and the /// current thread proxy also continues executing without the need for a virtual processor root. The thread proxy is considered /// to have left the scheduler until it calls the IThreadProxy::SwitchOut /// method at a later point in time. The IThreadProxy::SwitchOut method could block the thread proxy until a virtual /// processor root is available to reschedule it. /// SwitchTo must be called on the IThreadProxy interface that represents the currently executing thread /// or the results are undefined. The function throws invalid_argument if the parameter /// is set to NULL. /// /// /**/ virtual void SwitchTo(_Inout_ IExecutionContext * pContext, SwitchingProxyState switchState) =0; /// /// Disassociates the context from the underlying virtual processor root. /// /// /// Indicates the state of the thread proxy that is executing the switch. The parameter is of type . /// /// /// Use SwitchOut if you need to disassociate a context from the virtual processor root it is executing on, for any reason. Depending /// on the value you pass in to the parameter , and whether or not it is executing on a virtual processor root, /// the call will either return immediately or block the thread proxy associated with the context. It is an error to call SwitchOut with /// the parameter set to Idle. Doing so will result in an invalid_argument exception. /// /// SwitchOut is useful when you want to reduce the number of virtual processor roots your scheduler has, either because the Resource /// Manager has instructed you to do so, or because you requested a temporary oversubscribed virtual processor root, and are done with it. /// In this case you should invoke the method on the virtual processor root, before making /// a call to SwitchOut with the parameter set to Blocking. This will block the thread proxy and it /// will resume execution when a different virtual processor root in the scheduler is available to execute it. The blocking thread proxy can be /// resumed by calling the function SwitchTo to switch to this thread proxy's execution context. You can also resume the thread proxy, /// by using its associated context to activate a virtual processor root. For more information on how to do this, see /// IVirtualProcessorRoot::Activate. /// /// SwitchOut may also be used when you want reinitialize the virtual processor so it may be activated in the future while either /// blocking the thread proxy or temporarily detaching it from the virtual processor root it is running on, and the scheduler it is dispatching /// work for. Use SwitchOut with the parameter set to Blocking if you wish to block the thread proxy. /// It can later be resumed using either SwitchTo or IVirtualProcessorRoot::Activate as noted above. Use SwitchOut with the /// parameter set to Nesting when you want to temporarily detach this thread proxy from the virtual processor root it is running on, /// and the scheduler the virtual processor is associated with. Calling SwitchOut with the parameter /// set to Nesting while it is executing on a virtual processor root will cause the root to be reinitialized and the current thread proxy /// to continue executing without the need for one. The thread proxy is considered to have left the scheduler until it calls the /// IThreadProxy::SwitchOut method with Blocking at a later point in time. The second /// call to SwitchOut with the parameter set to Blocking is intended to return the context to a blocked state so that it can be /// resumed by either SwitchTo or IVirtualProcessorRoot::Activate in the scheduler it detached from. Because it was not executing /// on a virtual processor root, no reinitialization takes place. /// /// A reinitialized virtual processor root is no different from a brand new virtual processor root your scheduler has been granted by the Resource /// Manager. You can use it for execution by activating it with an execution context using IVirtualProcessorRoot::Activate. /// /// SwitchOut must be called on the IThreadProxy interface that represents the currently executing thread /// or the results are undefined. /// /// In the libraries and headers that shipped with Visual Studio 2010, this method did not take a parameter and did not reinitialize the /// virtual processor root. To preserve old behavior when you upgrade to Visual Studio 2012, the default parameter value of Blocking is supplied. /// /**/ virtual void SwitchOut(SwitchingProxyState switchState = Blocking) =0; /// /// Causes the calling thread to yield execution to another thread that is ready to run on the current processor. The operating /// system selects the next thread to be executed. /// /// /// When called by a thread proxy backed by a regular Windows thread, YieldToSystem behaves exactly like the Windows function /// SwitchToThread. However, when called from user-mode schedulable (UMS) threads, the SwitchToThread function delegates the task /// of picking the next thread to run to the user mode scheduler, not the operating system. To achieve the desired effect of switching /// to a different ready thread in the system, use YieldToSystem. /// YieldToSystem must be called on the IThreadProxy interface that represents the currently executing thread /// or the results are undefined. /// /**/ virtual void YieldToSystem() = 0; }; /// /// The type of critical region a context is inside. /// /// /**/ enum CriticalRegionType { /// /// Indicates that the context is outside any critical region. /// /**/ OutsideCriticalRegion, /// /// Indicates that the context is inside a critical region. When inside a critical region, asynchronous suspensions are hidden from /// the scheduler. Should such a suspension happen, the Resource Manager will wait for the thread to become runnable and simply resume it instead /// of invoking the scheduler again. Any locks taken inside such a region must be taken with extreme care. /// /**/ InsideCriticalRegion, /// /// Indicates that the context is inside a hyper-critical region. When inside a hyper-critical region, both synchronous and asynchronous /// suspensions are hidden from the scheduler. Should such a suspension or blocking happen, the resource manager will wait for the thread to /// become runnable and simply resume it instead of invoking the scheduler again. Locks taken inside such a region must never be shared with /// code running outside such a region. Doing so will cause unpredictable deadlock. /// /**/ InsideHyperCriticalRegion }; /// /// An abstraction for a thread of execution. If you want your scheduler to be granted user-mode schedulable (UMS) threads, set the value for the /// scheduler policy element SchedulerKind to UmsThreadDefault, and implement the IUMSScheduler interface. /// UMS threads are only supported on 64-bit operating systems with version Windows 7 and higher. /// /// /// /**/ struct IUMSThreadProxy : public IThreadProxy { /// /// Called in order to enter a critical region. When inside a critical region, the scheduler will not observe asynchronous blocking operations /// that happen during the region. This means that the scheduler will not be reentered for page faults, thread suspensions, kernel asynchronous /// procedure calls (APCs), and so forth, for a UMS thread. /// /// /// The new depth of critical region. Critical regions are reentrant. /// /// /**/ virtual int EnterCriticalRegion() =0; /// /// Called in order to exit a critical region. /// /// /// The new depth of critical region. Critical regions are reentrant. /// /// /**/ virtual int ExitCriticalRegion() =0; /// /// Called in order to enter a hyper-critical region. When inside a hyper-critical region, the scheduler will not observe any blocking operations /// that happen during the region. This means the scheduler will not be reentered for blocking function calls, lock acquisition attempts which /// block, page faults, thread suspensions, kernel asynchronous procedure calls (APCs), and so forth, for a UMS thread. /// /// /// The new depth of hyper-critical region. Hyper-critical regions are reentrant. /// /// /// The scheduler must be extraordinarily careful about what methods it calls and what locks it acquires in such regions. If code in such a /// region blocks on a lock that is held by something the scheduler is responsible for scheduling, deadlock may ensue. /// /// /**/ virtual int EnterHyperCriticalRegion() =0; /// /// Called in order to exit a hyper-critical region. /// /// /// The new depth of hyper-critical region. Hyper-critical regions are reentrant. /// /// /**/ virtual int ExitHyperCriticalRegion() =0; /// /// Returns what kind of critical region the thread proxy is within. Because hyper-critical regions are a superset of critical regions, if code /// has entered a critical region and then a hyper-critical region, InsideHyperCriticalRegion will be returned. /// /// /// The type of critical region the thread proxy is within. /// /// /**/ virtual CriticalRegionType GetCriticalRegionType() const =0; }; /// /// An abstraction for a hardware thread. /// /// /// Execution resources can be standalone or associated with virtual processor roots. A standalone execution resource is created when /// a thread in your application creates a thread subscription. The methods /// ISchedulerProxy::SubscribeThread and /// ISchedulerProxy::RequestInitialVirtualProcessors create thread subscriptions, and return an IExecutionResource interface /// representing the subscription. Creating a thread subscription is a way to inform the Resource Manager that a given thread will participate /// in the work queued to a scheduler, along with the virtual processor roots Resource Manager assigns to the scheduler. /// The Resource Manager uses the information to avoid oversubscribing hardware threads where it can. /// /// /// /// /**/ struct IExecutionResource { /// /// Returns a unique identifier for the processor node that this execution resource belongs to. /// /// /// A unique identifier for a processor node. /// /// /// The Concurrency Runtime represents hardware threads on the system in groups of processor nodes. Nodes are usually derived from /// the hardware topology of the system. For example, all processors on a specific socket or a specific NUMA node may belong to the /// same processor node. The Resource Manager assigns unique identifiers to these nodes starting with 0 up to and including /// nodeCount - 1, where nodeCount represents the total number of processor nodes on the system. /// The count of nodes can be obtained from the function GetProcessorNodeCount. /// /**/ virtual unsigned int GetNodeId() const =0; /// /// Returns a unique identifier for the hardware thread that this execution resource represents. /// /// /// A unique identifier for the hardware thread underlying this execution resource. /// /// /// Each hardware thread is assigned a unique identifier by the Concurrency Runtime. If multiple execution resources are associated /// hardware thread, they will all have the same execution resource identifier. /// /**/ virtual unsigned int GetExecutionResourceId() const =0; /// /// Returns this execution resource to the Resource Manager. /// /// /// An interface to the scheduler making the request to remove this execution resource. /// /// /// Use this method to return standalone execution resources as well as execution resources associated with virtual processor roots to /// the Resource Manager. /// If this is a standalone execution resource you received from either of the methods /// ISchedulerProxy::SubscribeCurrentThread or /// ISchedulerProxy::RequestInitialVirtualProcessors, calling the method Remove will end the thread subscription that the /// resource was created to represent. You are required to end all thread subscriptions before shutting down a scheduler proxy, and must /// call Remove from the thread that created the subscription. /// Virtual processor roots, too, can be returned to the Resource Manager by invoking the Remove method, because the interface /// IVirtualProcessorRoot inherits from the IExecutionResource interface. You may need to return a virtual processor root either /// in response to a call to the IScheduler::RemoveVirtualProcessors /// method, or when you are done with an oversubscribed virtual processor root you obtained from the /// ISchedulerProxy::CreateOversubscriber method. For virtual processor roots, there are no restrictions on which thread can invoke /// the Remove method. /// invalid_argument is thrown if the parameter is set to NULL. /// invalid_operation is thrown if the parameter is different from the scheduler that this /// execution resource was created for, or, with a standalone execution resource, if the current thread is different from the /// thread that created the thread subscription. /// /// /// /**/ virtual void Remove(_Inout_ IScheduler * pScheduler) =0; /// /// Returns the number of activated virtual processor roots and subscribed external threads currently associated with the underlying /// hardware thread this execution resource represents. /// /// /// The current subscription level. /// /// /// The subscription level tells you how many running threads are associated with the hardware thread. This only includes threads /// the Resource Manager is aware of in the form of subscribed threads, and virtual processor roots that are actively executing /// thread proxies. /// Calling the method ISchedulerProxy::SubscribeCurrentThread, /// or the method ISchedulerProxy::RequestInitialVirtualProcessors /// with the parameter set to the value true increments the subscription /// level of a hardware thread by one. They also return an IExecutionResource interface representing the subscription. A /// corresponding call to the IExecutionResource::Remove decrements the /// hardware thread's subscription level by one. /// The act of activating a virtual processor root using the method /// IVirtualProcessorRoot::Activate increments the subscription level of a hardware thread by one. The methods /// IVirtualProcessorRoot::Deactivate, or /// IExecutionResource::Remove decrement the subscription level by one /// when invoked on an activated virtual processor root. /// The Resource Manager uses subscription level information as one of the ways in which to determine when to move resources /// between schedulers. /// /**/ virtual unsigned int CurrentSubscriptionLevel() const =0; }; /// /// An abstraction for a hardware thread on which a thread proxy can execute. /// /// /// Every virtual processor root has an associated execution resource. The IVirtualProcessorRoot interface inherits from the /// IExecutionResource interface. Multiple virtual processor roots may correspond to the same /// underlying hardware thread. /// The Resource Manager grants virtual processor roots to schedulers in response to requests for resources. A scheduler can use /// a virtual processor root to perform work by activating it with an execution context. /// /**/ struct IVirtualProcessorRoot : public IExecutionResource { /// /// Returns a unique identifier for the virtual processor root. /// /// /// An integer identifier. /// /**/ virtual unsigned int GetId() const =0; /// /// Causes the thread proxy associated with the execution context interface to start executing on this /// virtual processor root. /// /// /// An interface to the execution context that will be dispatched on this virtual processor root. /// /// /// The Resource Manager will supply a thread proxy if one is not associated with the execution context interface /// The Activate method can be used to start executing work on a new virtual processor root returned by the Resource Manager, or to resume /// the thread proxy on a virtual processor root that has deactivated or is about to deactivate. See /// IVirtualProcessorRoot::Deactivate for more information on deactivation. When you are resuming a deactivated virtual processor /// root, the parameter must be the same as the parameter used to deactivate the virtual processor root. /// Once a virtual processor root has been activated for the first time, subsequent pairs of calls to Deactivate and /// Activate may race with each other. This means it is acceptable for the Resource Manager to receive a call to Activate /// before it receives the Deactivate call it was meant for. /// When you activate a virtual processor root, you signal to the Resource Manager that this virtual processor root is currently /// busy with work. If your scheduler cannot find any work to execute on this root, it is expected to invoke the Deactivate method /// informing the Resource Manager that the virtual processor root is idle. The Resource Manager uses this data to /// load balance the system. /// invalid_argument is thrown if the argument has the value NULL. /// invalid_operation is thrown if the argument does not represent the execution context that /// was most recently dispatched by this virtual processor root. /// The act of activating a virtual processor root increases the subscription level of the underlying hardware thread by one. For more /// information on subscription levels, see /// IExecutionResource::CurrentSubscriptionLevel. /// /// /// /**/ virtual void Activate(_Inout_ IExecutionContext * pContext) =0; /// /// Causes the thread proxy currently executing on this virtual processor root to stop dispatching the execution context. The thread proxy /// will resume executing on a call to the Activate method. /// /// /// The context which is currently being dispatched by this root. /// /// /// A boolean value. A value of true indicates that the thread proxy returned from the Deactivate method in response to /// a call to the Activate method. A value of false indicates that the thread proxy returned from the method in response /// to a notification event in the Resource Manager. On a user-mode schedulable (UMS) thread scheduler, this indicates that items have /// appeared on the scheduler's completion list, and the scheduler is required to handle them. /// /// /// Use this method to temporarily stop executing a virtual processor root when you cannot find any work in your scheduler. /// A call to the Deactivate method must originate from within the Dispatch method of the execution context that /// the virtual processor root was last activated with. In other words, the thread proxy invoking the Deactivate method /// must be the one that is currently executing on the virtual processor root. Calling the method on a virtual processor /// root you are not executing on could result in undefined behavior. /// A deactivated virtual processor root may be woken up with a call to the Activate method, with the same /// argument that was passed in to the Deactivate method. The scheduler is responsible for ensuring that calls to the Activate /// and Deactivate methods are paired, but they are not required to be received in a specific order. The Resource /// Manager can handle receiving a call to the Activate method before it receives a call to the Deactivate method it was /// meant for. /// If a virtual processor root awakens and the return value from the Deactivate method is the value false, the scheduler /// should query the UMS completion list via the IUMSCompletionList::GetUnblockNotifications method, act on that information, and /// then subsequently call the Deactivate method again. This should be repeated until such time as the Deactivate method returns /// the value true. /// invalid_argument is thrown if the argument has the value NULL. /// invalid_operation is thrown if the virtual processor root has never been activated, or the argument /// does not represent the execution context that was most recently dispatched by this virtual processor root. /// The act of deactivating a virtual processor root decreases the subscription level of the underlying hardware thread by one. For /// more information on subscription levels, see /// IExecutionResource::CurrentSubscriptionLevel. /// /// /// /// /**/ virtual bool Deactivate(_Inout_ IExecutionContext * pContext) =0; /// /// Causes data stored in the memory hierarchy of individual processors to become visible to all processors on the system. /// It ensures that a full memory fence has been executed on all processors before the method returns. /// /// /// The context which is currently being dispatched by this virtual processor root. /// /// /// You may find this method useful when you want to synchronize deactivation of a virtual processor root with the addition of new work into /// the scheduler. For performance reasons, you may decide to add work items to your scheduler without executing a memory barrier, which /// means work items added by a thread executing on one processor are not immediately visible to all other processors. By using this method /// in conjunction with the Deactivate method you can ensure that your scheduler does not deactivate all its virtual processor /// roots while work items exist in your scheduler's collections. /// A call to the EnsureAllTasksVisibleThe method must originate from within the Dispatch method of the execution /// context that the virtual processor root was last activated with. In other words, the thread proxy invoking the EnsureAllTasksVisible /// method must be the one that is currently executing on the virtual processor root. Calling the method on a virtual processor /// root you are not executing on could result in undefined behavior. /// invalid_argument is thrown if the argument has the value NULL. /// invalid_operation is thrown if the virtual processor root has never been activated, or the argument /// does not represent the execution context that was most recently dispatched by this virtual processor root. /// /// /**/ virtual void EnsureAllTasksVisible(_Inout_ IExecutionContext *pContext) =0; }; /// /// An interface to an abstraction of a work scheduler. The Concurrency Runtime's Resource Manager uses this interface to communicate with work /// schedulers. /// /// /// If you are implementing a custom scheduler that communicates with the Resource Manager, you should provide an implementation of the /// IScheduler interface. This interface is one end of a two-way channel of communication between a scheduler and the /// Resource Manager. The other end is represented by the IResourceManager and ISchedulerProxy interfaces which are /// implemented by the Resource Manager. /// /// /// /// /// /// /// /**/ struct IScheduler { /// /// Returns a unique identifier for the scheduler. /// /// /// A unique integer identifier. /// /// /// You should use the GetSchedulerId function to obtain a unique identifier for the object /// that implements the IScheduler interface, before you use the interface as a parameter to methods supplied by the Resource Manager. /// You are expected to return the same identifier when the GetId function is invoked. An identifier obtained from a different /// source could result in undefined behavior. /// /**/ virtual unsigned int GetId() const =0; /// /// Provides information related to task arrival and completion rates, and change in queue length for a scheduler. /// /// /// The number of tasks that have been completed by the scheduler since the last call to this method. /// /// /// The number of tasks that have arrived in the scheduler since the last call to this method. /// /// /// The total number of tasks in all scheduler queues. /// /// /// This method is invoked by the Resource Manager in order to gather statistics for a scheduler. The statistics gathered here /// will be used to drive dynamic feedback algorithms to determine when it is appropriate to assign more resources to /// the scheduler and when to take resources away. The values provided by the scheduler can be optimistic and do not necessarily /// have to reflect the current count accurately. /// You should implement this method if you want the Resource Manager to use feedback about such things as task arrival to determine /// how to balance resource between your scheduler and other schedulers registered with the Resource Manager. If you choose not to /// gather statistics, you can set the policy key DynamicProgressFeedback to the value DynamicProgressFeedbackDisabled /// in your scheduler's policy, and the Resource Manager will not invoke this method on your scheduler. /// In the absence of statistical information, the Resource Manager will use hardware thread subscription levels to make /// resource allocation and migration decisions. For more information on subscription levels, see /// IExecutionResource::CurrentSubscriptionLevel. /// /// /// /**/ virtual void Statistics(_Out_ unsigned int * pTaskCompletionRate, _Out_ unsigned int * pTaskArrivalRate, _Out_ unsigned int * pNumberOfTasksEnqueued) =0; /// /// Returns a copy of the scheduler's policy. For more information on scheduler policies, see /// SchedulerPolicy. /// /// /// A copy of the scheduler's policy. /// /// /**/ virtual SchedulerPolicy GetPolicy() const =0; /// /// Provides a scheduler with a set of virtual processor roots for its use. Each IVirtualProcessorRoot interface represents /// the right to execute a single thread that can perform work on behalf of the scheduler. /// /// /// An array of IVirtualProcessorRoot interfaces representing the virtual processor roots being added to the scheduler. /// /// /// The number of IVirtualProcessorRoot interfaces in the array. /// /// /// The Resource Manager invokes the AddVirtualProcessor method to grant an initial set of virtual processor roots to /// a scheduler. It could also invoke the method to add virtual processor roots to the scheduler when it rebalances resources /// among schedulers. /// /// /// /**/ virtual void AddVirtualProcessors(_In_reads_(count) IVirtualProcessorRoot ** ppVirtualProcessorRoots, unsigned int count) =0; /// /// Initiates the removal of virtual processor roots that were previously allocated to this scheduler. /// /// /// An array of IVirtualProcessorRoot interfaces representing the virtual processor roots to be removed. /// /// /// The number of IVirtualProcessorRoot interfaces in the array. /// /// /// The Resource Manager invokes the RemoveVirtualProcessors method to take back a set of virtual processor roots from /// a scheduler. The scheduler is expected to invoke the Remove method on each /// interface when it is done with the virtual processor roots. Do not use an IVirtualProcessorRoot interface once you have /// invoked the Remove method on it. /// The parameter points to an array of interfaces. Among the set of virtual processor /// roots to be removed, the roots have never been activated can be returned immediately using the Remove method. /// The roots that have been activated and are either executing work, or have been deactivated and are waiting for work to arrive, should be /// returned asynchronously. The scheduler must make every attempt to remove the virtual processor root as quickly as possible. /// Delaying removal of the virtual processor roots may result in unintentional oversubscription within the scheduler. /// /// /// /**/ virtual void RemoveVirtualProcessors(_In_reads_(count) IVirtualProcessorRoot ** ppVirtualProcessorRoots, unsigned int count) =0; /// /// Notifies this scheduler that the hardware threads represented by the set of virtual processor roots in the array /// are not being used by other schedulers. /// /// /// An array of IVirtualProcessorRoot interfaces associated with hardware threads on which other schedulers have become idle. /// /// /// The number of IVirtualProcessorRoot interfaces in the array. /// /// /// It is possible for a particular hardware thread to be assigned to multiple schedulers at the same time. One reason for this could be /// that there are not enough hardware threads on the system to satisfy the minimum concurrency for all schedulers, without sharing resources. /// Another possibility is that resources are temporarily assigned to other schedulers when the owning scheduler is not using them, by way of /// all its virtual processor roots on that hardware thread being deactivated. /// The subscription level of a hardware thread is denoted by the number of subscribed threads and activated virtual processor roots associated /// with that hardware thread. From a particular scheduler's point of view, the external subscription level of a hardware thread is the portion /// of the subscription other schedulers contribute to. Notifications that resources are externally busy are sent to a scheduler when the external /// subscription level for a hardware thread falls to zero from a previous positive value. /// Notifications via this method are only sent to schedulers that have a policy where the value for the MinConcurrency /// policy key is equal to the value for the MaxConcurrency policy key. For more information on scheduler policies, /// see SchedulerPolicy. /// A scheduler that qualifies for notifications gets a set of initial notifications when it is created, informing it whether the /// resources it was just assigned are externally busy or idle. /// /// /// /**/ virtual void NotifyResourcesExternallyIdle(_In_reads_(count) IVirtualProcessorRoot ** ppVirtualProcessorRoots, unsigned int count) =0; /// /// Notifies this scheduler that the hardware threads represented by the set of virtual processor roots in the array /// are now being used by other schedulers. /// /// /// An array of IVirtualProcessorRoot interfaces associated with the hardware threads on which other schedulers have become busy. /// /// /// The number of IVirtualProcessorRoot interfaces in the array. /// /// /// It is possible for a particular hardware thread to be assigned to multiple schedulers at the same time. One reason for this could be /// that there are not enough hardware threads on the system to satisfy the minimum concurrency for all schedulers, without sharing resources. /// Another possibility is that resources are temporarily assigned to other schedulers when the owning scheduler is not using them, by way of /// all its virtual processor roots on that hardware thread being deactivated. /// The subscription level of a hardware thread is denoted by the number of subscribed threads and activated virtual processor roots associated /// with that hardware thread. From a particular scheduler's point of view, the external subscription level of a hardware thread is the portion /// of the subscription other schedulers contribute to. Notifications that resources are externally busy are sent to a scheduler when the external /// subscription level for a hardware thread moves from zero into positive territory. /// Notifications via this method are only sent to schedulers that have a policy where the value for the MinConcurrency /// policy key is equal to the value for the MaxConcurrency policy key. For more information on scheduler policies, /// see SchedulerPolicy. /// A scheduler that qualifies for notifications gets a set of initial notifications when it is created, informing it whether the /// resources it was just assigned are externally busy or idle. /// /// /// /**/ virtual void NotifyResourcesExternallyBusy(_In_reads_(count) IVirtualProcessorRoot ** ppVirtualProcessorRoots, unsigned int count) =0; }; /// /// Represents a notification from the Resource Manager that a thread proxy which blocked and triggered a return to the scheduler's /// designated scheduling context has unblocked and is ready to be scheduled. This interface is invalid once the thread proxy's /// associated execution context, returned from the GetContext method, is rescheduled. /// /// /// /**/ struct IUMSUnblockNotification { /// /// Returns the IExecutionContext interface for the execution context associated with the thread proxy which has /// unblocked. Once this method returns and the underlying execution context has been rescheduled via a call to the /// IThreadProxy::SwitchTo method, this interface is no longer valid. /// /// /// An IExecutionContext interface for the execution context to a thread proxy which has unblocked. /// /**/ virtual IExecutionContext* GetContext() =0; /// /// Returns the next IUMSUnblockNotification interface in the chain returned from the method /// IUMSCompletionList::GetUnblockNotifications. /// /// /// The next IUMSUnblockNotification interface in the chain returned from the method IUMSCompletionList::GetUnblockNotifications. /// /**/ virtual IUMSUnblockNotification* GetNextUnblockNotification() =0; }; /// /// Represents a UMS completion list. When a UMS thread blocks, the scheduler's designated scheduling context is dispatched /// in order to make a decision of what to schedule on the underlying virtual processor root while the original thread is blocked. When the /// original thread unblocks, the operating system queues it to the completion list which is accessible through this interface. The scheduler can /// query the completion list on the designated scheduling context or any other place it searches for work. /// /// /// A scheduler must be extraordinarily careful about what actions are performed after utilizing this interface to dequeue items from the completion /// list. The items should be placed on the scheduler's list of runnable contexts and be generally accessible as soon as possible. It is entirely /// possible that one of the dequeued items has been given ownership of an arbitrary lock. The scheduler can make no arbitrary function calls that may /// block between the call to dequeue items and the placement of those items on a list that can be generally accessed from within the scheduler. /// /// /// /**/ struct IUMSCompletionList { /// /// Retrieves a chain of IUMSUnblockNotification interfaces representing execution contexts whose associated thread proxies /// have unblocked since the last time this method was invoked. /// /// /// A chain of IUMSUnblockNotification interfaces. /// /// /// The returned notifications are invalid once the execution contexts are rescheduled. /// /// /**/ virtual IUMSUnblockNotification *GetUnblockNotifications() =0; }; /// /// An interface to an abstraction of a work scheduler that wants the Concurrency Runtime's Resource Manager to hand it user-mode /// schedulable (UMS) threads. The Resource Manager uses this interface to communicate with UMS thread schedulers. The IUMSScheduler interface /// inherits from the IScheduler interface. /// /// /// If you are implementing a custom scheduler that communicates with the Resource Manager, and you want UMS threads to be handed to your scheduler /// instead of ordinary Win32 threads, you should provide an implementation of the IUMSScheduler interface. In addition, you should set the /// policy value for the scheduler policy key SchedulerKind to be UmsThreadDefault. If the policy specifies UMS thread, the /// IScheduler interface that is passed as a parameter to the IResourceManager::RegisterScheduler /// method must be an IUMSScheduler interface. /// The Resource Manager is able to hand you UMS threads only on operating systems that have the UMS feature. 64-bit operating systems with /// version Windows 7 and higher support UMS threads. If you create a scheduler policy with the SchedulerKind key set to the value /// UmsThreadDefault and the underlying platform does not support UMS, the value of the SchedulerKind key on that policy will /// be changed to the value ThreadScheduler. You should always read back this policy value before expecting to receive UMS threads. /// The IUMSScheduler interface is one end of a two-way channel of communication between a scheduler and the Resource Manager. /// The other end is represented by the IResourceManager and ISchedulerProxy interfaces, which are implemented by the Resource Manager. /// /// /// /// /// /**/ struct IUMSScheduler : public IScheduler { /// /// Assigns an IUMSCompletionList interface to a UMS thread scheduler. /// /// /// The completion list interface for the scheduler. There is a single list per scheduler. /// /// /// The Resource Manager will invoke this method on a scheduler that specifies it wants UMS threads, after the scheduler has requested an initial /// allocation of resources. The scheduler can use the IUMSCompletionList interface to determine when UMS thread proxies have unblocked. /// It is only valid to access this interface from a thread proxy running on a virtual processor root assigned to the UMS scheduler. /// /// /// /**/ virtual void SetCompletionList(_Inout_ IUMSCompletionList * pCompletionList) =0; }; /// /// The interface by which schedulers communicate with the Concurrency Runtime's Resource Manager to negotiate resource allocation. /// /// /// The Resource Manager hands an ISchedulerProxy interface to every scheduler that registers with it using the /// IResourceManager::RegisterScheduler method. /// /// /// /// /// /**/ struct ISchedulerProxy { /// /// Requests an initial allocation of virtual processor roots. Every virtual processor root represents the ability to execute one thread /// that can perform work for the scheduler. /// /// /// Whether to subscribe the current thread and account for it during resource allocation. /// /// /// The IExecutionResource interface for the current thread, if the parameter has /// the value true. If the value is false, the method returns NULL. /// /// /// Before a scheduler executes any work, it should use this method to request virtual processor roots from the Resource Manager. The Resource /// Manager will access the scheduler's policy using IScheduler::GetPolicy and use the /// values for the policy keys MinConcurrency, MaxConcurrency and TargetOversubscriptionFactor to determine how many /// hardware threads to assign to the scheduler initially and how many virtual processor roots to create for every hardware thread. /// For more information on how scheduler policies are used to determine a scheduler's initial allocation, see /// PolicyElementKey. /// The Resource Manager grants resources to a scheduler by calling the method /// IScheduler::AddVirtualProcessors with a list of virtual processor roots. The method is invoked as a callback into the scheduler /// before this method returns. /// If the scheduler requested subscription for the current thread by setting the parameter /// to true, the method returns an IExecutionResource interface. The subscription must be terminated at a later point by using /// the IExecutionResource::Remove method. /// When determining which hardware threads are selected, the Resource Manager will attempt to optimize for processor node affinity. /// If subscription is requested for the current thread, it is an indication that the current thread intends to participate in the work assigned /// to this scheduler. In such a case, the allocated virtual processors roots are located on the processor node the current thread is executing on, /// if possible. /// The act of subscribing a thread increases the subscription level of the underlying hardware thread by one. The subscription level is /// reduced by one when the subscription is terminated. For more information on subscription levels, see /// IExecutionResource::CurrentSubscriptionLevel. /// /**/ virtual IExecutionResource * RequestInitialVirtualProcessors(bool doSubscribeCurrentThread) =0; /// /// Notifies the Resource Manager that the scheduler is shutting down. This will cause the Resource Manager to immediately reclaim /// all resources granted to the scheduler. /// /// /// All IExecutionContext interfaces the scheduler received as a result of subscribing an external thread using the methods /// ISchedulerProxy::RequestInitialVirtualProcessors or ISchedulerProxy::SubscribeCurrentThread must be returned to the Resource /// Manager using IExecutionResource::Remove before a scheduler shuts itself down. /// If your scheduler had any deactivated virtual processor roots, you must activate them using /// IVirtualProcessorRoot::Activate, and have the thread proxies executing on them leave the Dispatch method of the execution contexts /// they are dispatching before you invoke Shutdown on a scheduler proxy. /// It is not necessary for the scheduler to individually return all of the virtual processor roots the Resource Manager granted to it via /// calls to the Remove method because all virtual processors roots will be returned to the Resource Manager at shutdown. /// /// /// /// /**/ virtual void Shutdown() =0; /// /// Associates an execution context with a thread proxy, if it is not already associated with one. /// /// /// An interface to the execution context to associate with a thread proxy. /// /// /// Normally, the IThreadProxy::SwitchTo method will bind a thread proxy to an /// execution context on demand. There are, however, circumstances where it is necessary to bind a context in advance /// to ensure that the SwitchTo method switches to an already bound context. This is the case on a UMS scheduling context as it /// cannot call methods that allocate memory, and binding a thread proxy may involve memory allocation if a thread proxy is not readily /// available in the free pool of the thread proxy factory. /// invalid_argument is thrown if the parameter has the value NULL. /// /// /**/ virtual void BindContext(_Inout_ IExecutionContext * pContext) =0; /// /// Disassociates a thread proxy from the execution context specified by the parameter and returns it /// to the thread proxy factory's free pool. This method may only be called on an execution context which was bound via the /// ISchedulerProxy::BindContext method and has not yet been started via being /// the pContext parameter of an IThreadProxy::SwitchTo method call. /// /// /// The execution context to disassociate from its thread proxy. /// /**/ virtual void UnbindContext(_Inout_ IExecutionContext * pContext) =0; /// /// Registers the current thread with the Resource Manager, associating it with this scheduler. /// /// /// The IExecutionResource interfacing representing the current thread in the runtime. /// /// /// Use this method if you want the Resource Manager to account for the current thread while allocating resources to your scheduler and other /// schedulers. It is especially useful when the thread plans to participate in the work queued to your scheduler, along with the virtual /// processor roots the scheduler receives from the Resource Manager. The Resource Manager uses information to prevent unnecessary oversubscription /// of hardware threads on the system. /// The execution resource received via this method should be returned to the Resource Manager using the /// IExecutionResource::Remove method. The thread that calls the Remove method must be /// the same thread that previously called the SubscribeCurrentThread method. /// The act of subscribing a thread increases the subscription level of the underlying hardware thread by one. The subscription level is /// reduced by one when the subscription is terminated. For more information on subscription levels, see /// IExecutionResource::CurrentSubscriptionLevel. /// /**/ virtual IExecutionResource * SubscribeCurrentThread() =0; /// /// Creates a new virtual processor root on the hardware thread associated with an existing execution resource. /// /// /// An IExecutionResource interface that represents the hardware thread you want to oversubscribe. /// /// /// An IVirtualProcessorRoot interface. /// /// /// Use this method when your scheduler wants to oversubscribe a particular hardware thread for a limited amount of time. Once you are /// done with the virtual processor root, you should return it to the resource manager by calling the /// Remove method on the IVirtualProcessorRoot interface. /// You can even oversubscribe an existing virtual processor root, because the IVirtualProcessorRoot interface inherits from the /// IExecutionResource interface. /// /**/ virtual IVirtualProcessorRoot * CreateOversubscriber(_Inout_ IExecutionResource * pExecutionResource) =0; }; /// /// An interface to an execution resource as defined by the Resource Manager. /// /// /// This interface is typically utilized to walk the topology of the system as observed by the Resource Manager. /// /**/ struct ITopologyExecutionResource { /// /// Returns an interface to the next execution resource in enumeration order. /// /// /// An interface to the next execution resource in enumeration order. If there are no more nodes in enumeration order of the node to which /// this execution resource belongs, this method will return the value NULL. /// /// /// /**/ virtual ITopologyExecutionResource *GetNext() const =0; /// /// Returns the Resource Manager's unique identifier for this execution resource. /// /// /// The Resource Manager's unique identifier for this execution resource. /// /**/ virtual unsigned int GetId() const =0; }; /// /// An interface to a topology node as defined by the Resource Manager. A node contains one or more execution resources. /// /// /// This interface is typically utilized to walk the topology of the system as observed by the Resource Manager. /// /**/ struct ITopologyNode { /// /// Returns an interface to the next topology node in enumeration order. /// /// /// An interface to the next node in enumeration order. If there are no more nodes in enumeration order of the system topology, this method /// will return the value NULL. /// /// /// /**/ virtual ITopologyNode *GetNext() const =0; /// /// Returns the Resource Manager's unique identifier for this node. /// /// /// The Resource Manager's unique identifier for this node. /// /// /// The Concurrency Runtime represents hardware threads on the system in groups of processor nodes. Nodes are usually derived from /// the hardware topology of the system. For example, all processors on a specific socket or a specific NUMA node may belong to the /// same processor node. The Resource Manager assigns unique identifiers to these nodes starting with 0 up to and including /// nodeCount - 1, where nodeCount represents the total number of processor nodes on the system. /// The count of nodes can be obtained from the function GetProcessorNodeCount. /// /**/ virtual unsigned int GetId() const =0; /// /// Returns the Windows assigned NUMA node number to which this Resource Maanger node belongs. /// /// /// The Windows assigned NUMA node number to which this Resource Manager node belongs. /// /// /// A thread proxy running on a virtual processor root belonging to this node will have affinity to at least the NUMA node level for the NUMA /// node returned by this method. /// /**/ virtual unsigned long GetNumaNode() const =0; /// /// Returns the number of execution resources grouped together under this node. /// /// /// The number of execution resources grouped together under this node. /// /// /**/ virtual unsigned int GetExecutionResourceCount() const =0; /// /// Returns the first execution resource grouped under this node in enumeration order. /// /// /// The first execution resource grouped under this node in enumeration order. /// /// /**/ virtual ITopologyExecutionResource *GetFirstExecutionResource() const =0; }; /// /// Indicates support of the Resource Manager interface defined in Visual Studio 2010. /// /**/ const unsigned int CONCRT_RM_VERSION_1 = 0x00010000; /// /// An interface to the Concurrency Runtime's Resource Manager. This is the interface by which schedulers communicate with the /// Resource Manager. /// /// /// Use the CreateResourceManager function to obtain an interface to the singleton Resource Manager /// instance. The method increments a reference count on the Resource Manager, and you should invoke the /// IResourceManager::Release method to release the reference when you are done with Resource Manager. Typically, each scheduler /// you create will invoke this method during creation, and release the reference to the Resource Manager after it shuts down. /// /// /// /**/ struct IResourceManager { /// /// Increments the reference count on the Resource Manager instance. /// /// /// The resulting reference count. /// /// /**/ virtual unsigned int Reference() =0; /// /// Decrements the reference count on the Resource Manager instance. The Resource Manager is destroyed when its reference count goes to 0. /// /// /// The resulting reference count. /// /// /// /**/ virtual unsigned int Release() =0; /// /// Registers a scheduler with the Resource Manager. Once the scheduler is registered, it should communicate with the Resource Manager using the /// ISchedulerProxy interface that is returned. /// /// /// An IScheduler interface to the scheduler to be registered. /// /// /// The version of communication interface the scheduler is using to communicate with the Resource Manager. Using a version allows the Resource /// Manager to evolve the communication interface while allowing schedulers to obtain access to older features. Schedulers that wish to use Resource /// Manager features present in Visual Studio 2010 should use the version CONCRT_RM_VERSION_1. /// /// /// The ISchedulerProxy interface the Resource Manager has associated with your scheduler. Your scheduler should use this interface to /// communicate with Resource Manager from this point on. /// /// /// Use this method to initiate communication with the Resource Manager. The method associates the IScheduler interface for your scheduler /// with an ISchedulerProxy interface and hands it back to you. You can use the returned interface to request execution resources for use /// by your scheduler, or to subscribe threads with the Resource Manager. The Resource Manager will use policy elements from the scheduler policy /// returned by the IScheduler::GetPolicy method to determine what type of threads the scheduler will /// need to execute work. If your SchedulerKind policy key has the value UmsThreadDefault and the value is read back out of the /// policy as the value UmsThreadDefault, the IScheduler interface passed to the method must be an IUMSScheduler interface. /// The method throws an invalid_argument exception if the parameter has the value NULL or if the /// parameter is not a valid version for the communication interface. /// /// /// /// /// /**/ virtual ISchedulerProxy *RegisterScheduler(_Inout_ IScheduler * pScheduler, unsigned int version) =0; /// /// Returns the number of nodes available to the Resource Manager. /// /// /// The number of nodes available to the Resource Manager. /// /**/ virtual unsigned int GetAvailableNodeCount() const =0; /// /// Returns the first node in enumeration order as defined by the Resource Manager. /// /// /// The first node in enumeration order as defined by the Resource Manager. /// /// /**/ virtual ITopologyNode* GetFirstNode() const =0; /// /// Present only in debug builds of the runtime, this method is a test hook designed to facilitate testing of the Resource Manager on varying hardware /// topologies, without requiring actual hardware matching the configuration. With retail builds of the runtime, this method will return without performing /// any action. /// /// /// The number of processor nodes being simulated. /// /// /// An array that specifies the number of cores on each node. /// /// /// A matrix specifying the node distance between any two nodes. This parameter can have the value NULL. /// /// /// An array that specifies the processor group each node belongs to. /// /// /// invalid_argument is thrown if the parameter has the value 0 was passed /// in, or if the parameter has the value NULL. /// invalid_operation is thrown if this method is called while other schedulers exist in the process. /// /**/ virtual void CreateNodeTopology(unsigned int nodeCount, _In_reads_(nodeCount) unsigned int * pCoreCount, _In_reads_opt_(nodeCount) unsigned int ** pNodeDistance, _In_reads_(nodeCount) unsigned int * pProcessorGroups) =0; /// /// An enumerated type that represents the operating system version. /// /**/ static enum OSVersion { /// /// An operating system prior to Windows XP. The Concurrency Runtime is not supported on operating /// systems with a version earlier than Windows XP with Service Pack 3. /// /**/ UnsupportedOS, /// /// The Windows XP operating system. /// /**/ XP, /// /// The Windows 2003 Server operating system. /// /**/ Win2k3, /// /// The Windows Vista and Windows Server 2008 operating systems. /// /**/ Vista, /// /// The Windows 7 and Windows Server 2008 R2 operating systems. /// /**/ Win7OrLater, /// /// This value is preserved for legacy reasons. The Concurrency Runtime in Visual Studio 2012 does not support Windows user-mode schedulable /// threads. /// /**/ UmsThreadAwareOS, /// /// Any operating system with version Windows 8 or higher. /// /**/ Win8OrLater }; }; /// /// Returns an interface that represents the singleton instance of the Concurrency Runtime's Resource Manager. The Resource Manager is responsible /// for assigning resources to schedulers that want to cooperate with each other. /// /// /// An IResourceManager interface. /// /// /// Multiple subsequent calls to this method will return the same instance of the Resource Manager. Each call to the method increments a reference /// count on the Resource Manager, and must be matched with a call to the IResourceManager::Release /// method when your scheduler is done communicating with the Resource Manager. /// unsupported_os is thrown if the operating system is not supported by the Concurrency Runtime. /// /// /**/ _CRTIMP IResourceManager* __cdecl CreateResourceManager(); /// /// Returns the operating system version. /// /// /// An enumerated value representing the operating system. /// /// /// unsupported_os is thrown if the operating system is not supported by the Concurrency Runtime. /// /// /**/ _CRTIMP IResourceManager::OSVersion __cdecl GetOSVersion(); /// /// Returns a unique identifier that can be assigned to a scheduler that implements the IScheduler interface. /// /// /// A unique identifier for a scheduler. /// /// /// Use this method to obtain an identifier for your scheduler before you pass an IScheduler interface as a parameter to any of the methods /// offered by the Resource Manager. /// /**/ _CRTIMP unsigned int __cdecl GetSchedulerId(); /// /// Returns a unique identifier that can be assigned to an execution context that implements the IExecutionContext interface. /// /// /// A unique identifier for an execution context. /// /// /// Use this method to obtain an identifier for your execution context before you pass an IExecutionContext interface as a parameter to any /// of the methods offered by the Resource Manager. /// /**/ _CRTIMP unsigned int __cdecl GetExecutionContextId(); /// /// Returns the number of hardware threads on the underlying system. /// /// /// The number of hardware threads. /// /// /// unsupported_os is thrown if the operating system is not supported by the Concurrency Runtime. /// /// /**/ _CRTIMP unsigned int __cdecl GetProcessorCount(); /// /// Returns the number of NUMA nodes or processor packages on the underlying system. /// /// /// The number of NUMA nodes or processor packages. /// /// /// If the system contains more NUMA nodes than processor packages, the number of NUMA nodes is returned, otherwise, the number of processor packages is returned. /// unsupported_os is thrown if the operating system is not supported by the Concurrency Runtime. /// /// /**/ _CRTIMP unsigned int __cdecl GetProcessorNodeCount(); #endif /* _CRT_USE_WINAPI_FAMILY_DESKTOP_APP */ } namespace concurrency = Concurrency; #pragma pack(pop)