Games Task Scheduler (GTS)
A multi-processor scheduling framework for games engines
gts::MicroScheduler Class Reference

A work-stealing task scheduler. The scheduler is executed by the WorkerPool it is initialized with. More...

#include <MicroScheduler.h>

Public Member Functions

 MicroScheduler ()
 Constructs a MicroScheduler in an uninitialized state. The user must call MicroScheduler::initialize to initialize the scheduler before use, otherwise calls to this MicroScheduler are undefined.
 
virtual ~MicroScheduler ()
 Implicitly shuts down the MicroScheduler if it's still running.
 
 MicroScheduler (MicroScheduler const &)=delete
 
MicroScheduleroperator= (MicroScheduler const &)=delete
 
bool initialize (WorkerPool *pWorkerPool)
 Initializes the MicroScheduler and attaches it to pWorkPool, where each worker in pWorkPool will execute submitted tasks. More...
 
bool initialize (MicroSchedulerDesc const &desc)
 Initializes the MicroScheduler for use. It creates the worker thread pool and allocates all memory to meet the requirements in desc. More...
 
void shutdown ()
 Stops the MicroScheduler and destroys all resources. The TaskSchuduler is now in an unusable state. All subsequent calls to this MicroScheduler are undefined.
 
template<typename TTask , typename... TArgs>
GTS_INLINE TTask * allocateTask (TArgs &&... args)
 Allocates a new Task object of type TTask. More...
 
template<typename TFunc , typename... TArgs>
GTS_INLINE TaskallocateTask (TFunc &&func, TArgs &&... args)
 Allocates a new Task object and emplaces the function/lambda data. More...
 
void spawnTask (Task *pTask, uint32_t priority=0)
 Spawns the specified 'pTask' to be executed by the scheduler. Spawned tasks are executed in LIFO order, and stolen in FIFO order. More...
 
void spawnTaskAndWait (Task *pTask, uint32_t priority=0)
 Spawns the specified 'pTask' to be executed by the scheduler and then waits for its reference count to become one. More...
 
void waitFor (Task *pTask)
 Waits for pTask's reference count to become one. More...
 
void waitForAll ()
 Waits for this MicroScheduler to have executed all it's tasks. More...
 
void destoryTask (Task *pTask)
 Manually destroy pTask. Undefined if this Task is executing.
 
GTS_INLINE void setActiveState (bool isActive)
 Sets the active state of this MicroScheduler. An active MicroScheduler will be run by the WorkerPool and a inactive MicroScheduler will be ignored. By default, an initialized MicroScheduler is active. More...
 
void addExternalVictim (MicroScheduler *pScheduler)
 Adds 'pScheduler' as an external victim. All Schedules in this MicroScheduler will be able to steal from pScheduler when they run out of work. More...
 
void removeExternalVictim (MicroScheduler *pScheduler)
 Removes 'pScheduler' as an external victim.
 
template<typename TFunc >
void registerCallback (MicroSchedulerCallbackType type, TFunc callback, void *pUserData)
 
template<typename TFunc >
void unregisterCallback (MicroSchedulerCallbackType type, TFunc callback, void *pUserData)
 
bool stealAndExecuteTask ()
 Tries to steal and execute a Task. More...
 
bool hasDemand (bool clear=false) const
 Checks if the LocalScheduler mapped to this thread has demand. More...
 
bool isRunning () const
 Checks if the scheduler is running. More...
 
bool hasTasks () const
 Checks if the scheduler has tasks. More...
 
bool hasExternalTasks () const
 Checks if the scheduler has external tasks. More...
 
uint32_t workerCount () const
 Get the worker count of the WorkerPool this scheduler is attached to. More...
 
OwnedId thisWorkerId () const
 Get the worker the Worker ID of the calling thread. More...
 
void wakeWorker ()
 Wake a sleeping Worker.
 
GTS_INLINE bool isActive () const
 Checks if the scheduler is active. More...
 
GTS_INLINE SubIdType id () const
 Get this schedulers ID. More...
 

Static Public Member Functions

static void resetIdGenerator ()
 Resets the ID generator to 0. This is not safe if there are any living MicroSchedulers.
 

Friends

class Task
 
class Worker
 
class WorkerPool
 
class LocalScheduler
 

Detailed Description

A work-stealing task scheduler. The scheduler is executed by the WorkerPool it is initialized with.

Supports: -Help-first work-stealing -Fork-join with nested parallelism -Arbitrary DAGs -Blocking joins -Continuation joins -Scheduler by-passing and task recycling optimizations -Task affinities. (Force a task to run on a specific thread.) -Task priorities with starvation resistance -Scheduler partitioning -Task execution isolation -Hierarchical work-stealing via external victims.

Todo:

Abstract into interface and make a concrete WorkStealingMicroScheduler. Interface will allow other algorithms to be explored.

Explore making priorities global to the scheduler. Currently they are only local to each thread.

Member Function Documentation

◆ addExternalVictim()

void gts::MicroScheduler::addExternalVictim ( MicroScheduler pScheduler)

Adds 'pScheduler' as an external victim. All Schedules in this MicroScheduler will be able to steal from pScheduler when they run out of work.

Remarks
This operation can be used to build a graph of MicroSchedulers. However, cycles will cause undefined behavior.
Parameters
pSchedulerThe victim to add.

◆ allocateTask() [1/2]

template<typename TTask , typename... TArgs>
GTS_INLINE TTask* gts::MicroScheduler::allocateTask ( TArgs &&...  args)
inline

Allocates a new Task object of type TTask.

Parameters
argsThe arguments for the TTask constructor.
Returns
The allocated Task or nullptr if the allocation failed.

◆ allocateTask() [2/2]

template<typename TFunc , typename... TArgs>
GTS_INLINE Task* gts::MicroScheduler::allocateTask ( TFunc &&  func,
TArgs &&...  args 
)
inline

Allocates a new Task object and emplaces the function/lambda data.

Parameters
funcA function that takes args as arguments.
argsThe arguments for func.
Returns
The allocated Task or nullptr if the allocation failed.

◆ hasDemand()

bool gts::MicroScheduler::hasDemand ( bool  clear = false) const

Checks if the LocalScheduler mapped to this thread has demand.

Returns
True if there is demand, false otherwise.

◆ hasExternalTasks()

bool gts::MicroScheduler::hasExternalTasks ( ) const

Checks if the scheduler has external tasks.

Returns
True if there are pending tasks in external victims, false otherwise.

◆ hasTasks()

bool gts::MicroScheduler::hasTasks ( ) const

Checks if the scheduler has tasks.

Returns
True if there are pending tasks, false otherwise.

◆ id()

GTS_INLINE SubIdType gts::MicroScheduler::id ( ) const
inline

Get this schedulers ID.

Returns
The unique ID of the scheduler.

◆ initialize() [1/2]

bool gts::MicroScheduler::initialize ( MicroSchedulerDesc const &  desc)

Initializes the MicroScheduler for use. It creates the worker thread pool and allocates all memory to meet the requirements in desc.

Parameters
descThe description of the MicroScheduler that describes how to initialize it.
Returns
True if the initialization succeeded, false otherwise.

◆ initialize() [2/2]

bool gts::MicroScheduler::initialize ( WorkerPool pWorkerPool)

Initializes the MicroScheduler and attaches it to pWorkPool, where each worker in pWorkPool will execute submitted tasks.

Parameters
pWorkerPoolThe WorkerPool to attach to.
Returns
True if the initialization succeeded, false otherwise.

◆ isActive()

GTS_INLINE bool gts::MicroScheduler::isActive ( ) const
inline

Checks if the scheduler is active.

Returns
True if the MicroScheduler is active, false otherwise.

◆ isRunning()

bool gts::MicroScheduler::isRunning ( ) const

Checks if the scheduler is running.

Returns
True if the scheduler is running, false otherwise.

◆ registerCallback()

template<typename TFunc >
void gts::MicroScheduler::registerCallback ( MicroSchedulerCallbackType  type,
TFunc  callback,
void *  pUserData 
)
inline

Registers a user callback function.

◆ setActiveState()

GTS_INLINE void gts::MicroScheduler::setActiveState ( bool  isActive)
inline

Sets the active state of this MicroScheduler. An active MicroScheduler will be run by the WorkerPool and a inactive MicroScheduler will be ignored. By default, an initialized MicroScheduler is active.

Parameters
isActiveTrue to mark as active. False to mark as inactive.

◆ spawnTask()

void gts::MicroScheduler::spawnTask ( Task pTask,
uint32_t  priority = 0 
)

Spawns the specified 'pTask' to be executed by the scheduler. Spawned tasks are executed in LIFO order, and stolen in FIFO order.

Parameters
pTaskThe Task to spawn. It will be destroyed after execution refCount == 1. In the rare situation you want to keep the task alive, add an extra reference. Doing this will require you to call Task::destroy when you are done to avoid memory leaks.
priorityThe priority of the Task.

◆ spawnTaskAndWait()

void gts::MicroScheduler::spawnTaskAndWait ( Task pTask,
uint32_t  priority = 0 
)

Spawns the specified 'pTask' to be executed by the scheduler and then waits for its reference count to become one.

There are two blocking behaviors:

  1. If spawnTaskAndWait is called from a worker thread, it will execute other tasks until pTask is complete.
  2. If spawnTaskAndWait is called from a non-worker thread, it will block until pTask is complete.
Parameters
pTaskThe Task to spawn.
priorityThe priority of the Task, if queued. Queuing occurs if this function is called on a non-worker thread or if this worker thread has a different affinity that the Task.

◆ stealAndExecuteTask()

bool gts::MicroScheduler::stealAndExecuteTask ( )

Tries to steal and execute a Task.

Returns
True if a Task was executed.
Remarks
Special method used by MacroScheduler algorithms. Not for general use.

◆ thisWorkerId()

OwnedId gts::MicroScheduler::thisWorkerId ( ) const

Get the worker the Worker ID of the calling thread.

Returns
The current Worker ID.

◆ unregisterCallback()

template<typename TFunc >
void gts::MicroScheduler::unregisterCallback ( MicroSchedulerCallbackType  type,
TFunc  callback,
void *  pUserData 
)
inline

Unregisters a user callback function.

◆ waitFor()

void gts::MicroScheduler::waitFor ( Task pTask)

Waits for pTask's reference count to become one.

There are two blocking behaviors:

  1. If waitFor is called from a worker thread, it will execute other tasks until pTask is complete.
  2. If waitFor is called from a non-worker thread, it will block until pTask is complete.
Parameters
pTaskThe Task to wait on. The Task must have an extra reference count for the wait before spawning, otherwise the MicroSchedule will destroy the task on completion. It is also up the caller to destroy this task once the wait in completed.

◆ waitForAll()

void gts::MicroScheduler::waitForAll ( )

Waits for this MicroScheduler to have executed all it's tasks.

There are two blocking behaviors:

  1. If waitFor is called from a worker thread, it will execute other tasks until complete.
  2. If waitFor is called from a non-worker thread, this function returns immediately.

◆ workerCount()

uint32_t gts::MicroScheduler::workerCount ( ) const

Get the worker count of the WorkerPool this scheduler is attached to.

Returns
The number of Workers in the WorkerPool.