Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
JobSystem Class Referenceabstract

#include <JobSystem.h>

Inheritance diagram for JobSystem:
NonCopyable JobSystemSingleThreaded JobSystemWithBarrier JobSystemThreadPool

Classes

class  Barrier
 A job barrier keeps track of a number of jobs and allows waiting until they are all completed. More...
 
class  Job
 A class that contains information for a single unit of work. More...
 
class  JobHandle
 

Public Types

using JobFunction = function< void()>
 Main function of the job.
 

Public Member Functions

virtual ~JobSystem ()=default
 Destructor.
 
virtual int GetMaxConcurrency () const =0
 Get maximum number of concurrently executing jobs.
 
virtual JobHandle CreateJob (const char *inName, ColorArg inColor, const JobFunction &inJobFunction, uint32 inNumDependencies=0)=0
 
virtual BarrierCreateBarrier ()=0
 Create a new barrier, used to wait on jobs.
 
virtual void DestroyBarrier (Barrier *inBarrier)=0
 Destroy a barrier when it is no longer used. The barrier should be empty at this point.
 
virtual void WaitForJobs (Barrier *inBarrier)=0
 Wait for a set of jobs to be finished, note that only 1 thread can be waiting on a barrier at a time.
 
- Public Member Functions inherited from NonCopyable
 NonCopyable ()=default
 
 NonCopyable (const NonCopyable &)=delete
 
void operator= (const NonCopyable &)=delete
 

Protected Member Functions

virtual void QueueJob (Job *inJob)=0
 Adds a job to the job queue.
 
virtual void QueueJobs (Job **inJobs, uint inNumJobs)=0
 Adds a number of jobs at once to the job queue.
 
virtual void FreeJob (Job *inJob)=0
 Frees a job.
 

Detailed Description

A class that allows units of work (Jobs) to be scheduled across multiple threads. It allows dependencies between the jobs so that the jobs form a graph.

The pattern for using this class is:

// Create job system
JobSystem *job_system = new JobSystemThreadPool(...);

// Create some jobs
JobHandle second_job = job_system->CreateJob("SecondJob", Color::sRed, []() { ... }, 1); // Create a job with 1 dependency
JobHandle first_job = job_system->CreateJob("FirstJob", Color::sGreen, [second_job]() { ....; second_job.RemoveDependency(); }, 0); // Job can start immediately, will start second job when it's done
JobHandle third_job = job_system->CreateJob("ThirdJob", Color::sBlue, []() { ... }, 0); // This job can run immediately as well and can run in parallel to job 1 and 2

// Add the jobs to the barrier so that we can execute them while we're waiting
Barrier *barrier = job_system->CreateBarrier();
barrier->AddJob(first_job);
barrier->AddJob(second_job);
barrier->AddJob(third_job);
job_system->WaitForJobs(barrier);

// Clean up
job_system->DestroyBarrier(barrier);
delete job_system;

Jobs are guaranteed to be started in the order that their dependency counter becomes zero (in case they're scheduled on a background thread) or in the order they're added to the barrier (when dependency count is zero and when executing on the thread that calls WaitForJobs).

If you want to implement your own job system, inherit from JobSystem and implement:

  • JobSystem::GetMaxConcurrency - This should return the maximum number of jobs that can run in parallel.
  • JobSystem::CreateJob - This should create a Job object and return it to the caller.
  • JobSystem::FreeJob - This should free the memory associated with the job object. It is called by the Job destructor when it is Release()-ed for the last time.
  • JobSystem::QueueJob/QueueJobs - These should store the job pointer in an internal queue to run immediately (dependencies are tracked internally, this function is called when the job can run). The Job objects are reference counted and are guaranteed to stay alive during the QueueJob(s) call. If you store the job in your own data structure you need to call AddRef() to take a reference. After the job has been executed you need to call Release() to release the reference. Make sure you no longer dereference the job pointer after calling Release().

JobSystem::Barrier is used to track the completion of a set of jobs. Jobs will be created by other jobs and added to the barrier while it is being waited on. This means that you cannot create a dependency graph beforehand as the graph changes while jobs are running. Implement the following functions:

  • Barrier::AddJob/AddJobs - Add a job to the barrier, any call to WaitForJobs will now also wait for this job to complete. If you store the job in a data structure in the Barrier you need to call AddRef() on the job to keep it alive and Release() after you're done with it.
  • Barrier::OnJobFinished - This function is called when a job has finished executing, you can use this to track completion and remove the job from the list of jobs to wait on.

The functions on JobSystem that need to be implemented to support barriers are:

  • JobSystem::CreateBarrier - Create a new barrier.
  • JobSystem::DestroyBarrier - Destroy a barrier.
  • JobSystem::WaitForJobs - This is the main function that is used to wait for all jobs that have been added to a Barrier. WaitForJobs can execute jobs that have been added to the barrier while waiting. It is not wise to execute other jobs that touch physics structures as this can cause race conditions and deadlocks. Please keep in mind that the barrier is only intended to wait on the completion of the Jolt jobs added to it, if you scheduled any jobs in your engine's job system to execute the Jolt jobs as part of QueueJob/QueueJobs, you might still need to wait for these in this function after the barrier is finished waiting.

An example implementation is JobSystemThreadPool. If you don't want to write the Barrier class you can also inherit from JobSystemWithBarrier.

Member Typedef Documentation

◆ JobFunction

using JobSystem::JobFunction = function<void()>

Main function of the job.

Constructor & Destructor Documentation

◆ ~JobSystem()

virtual JobSystem::~JobSystem ( )
virtualdefault

Destructor.

Member Function Documentation

◆ CreateBarrier()

virtual Barrier * JobSystem::CreateBarrier ( )
pure virtual

Create a new barrier, used to wait on jobs.

Implemented in JobSystemSingleThreaded, and JobSystemWithBarrier.

◆ CreateJob()

virtual JobHandle JobSystem::CreateJob ( const char *  inName,
ColorArg  inColor,
const JobFunction inJobFunction,
uint32  inNumDependencies = 0 
)
pure virtual

Create a new job, the job is started immediately if inNumDependencies == 0 otherwise it starts when RemoveDependency causes the dependency counter to reach 0.

Implemented in JobSystemSingleThreaded, and JobSystemThreadPool.

◆ DestroyBarrier()

virtual void JobSystem::DestroyBarrier ( Barrier inBarrier)
pure virtual

Destroy a barrier when it is no longer used. The barrier should be empty at this point.

Implemented in JobSystemSingleThreaded, and JobSystemWithBarrier.

◆ FreeJob()

virtual void JobSystem::FreeJob ( Job inJob)
protectedpure virtual

Frees a job.

Implemented in JobSystemSingleThreaded, and JobSystemThreadPool.

◆ GetMaxConcurrency()

virtual int JobSystem::GetMaxConcurrency ( ) const
pure virtual

Get maximum number of concurrently executing jobs.

Implemented in JobSystemSingleThreaded, and JobSystemThreadPool.

◆ QueueJob()

virtual void JobSystem::QueueJob ( Job inJob)
protectedpure virtual

Adds a job to the job queue.

Implemented in JobSystemSingleThreaded, and JobSystemThreadPool.

◆ QueueJobs()

virtual void JobSystem::QueueJobs ( Job **  inJobs,
uint  inNumJobs 
)
protectedpure virtual

Adds a number of jobs at once to the job queue.

Implemented in JobSystemSingleThreaded, and JobSystemThreadPool.

◆ WaitForJobs()

virtual void JobSystem::WaitForJobs ( Barrier inBarrier)
pure virtual

Wait for a set of jobs to be finished, note that only 1 thread can be waiting on a barrier at a time.

Implemented in JobSystemSingleThreaded, and JobSystemWithBarrier.


The documentation for this class was generated from the following file: