Jobs Manual

About

A job is a threaded, reusable, independent work item (task). It can be queued to be executed with other jobs in a (parallel) pipeline.

Job

A custom job is based on maxon::JobInterfaceTemplate, maxon::JobResultInterface and maxon::JobInterface. The custom class contains data and implements the function call operator with the actual workload. A job instance is based on maxon::JobRef.

Warning
Make sure that a job has no additional, hidden dependencies like for example executing parallelized code internally.
// This example shows a job that returns a value.
// FactorialJob calculates the factorial of the given number.
class FactorialJob : public maxon::JobInterfaceTemplate<FactorialJob, maxon::UInt>
{
public:
FactorialJob() { };
MAXON_IMPLICIT FactorialJob(maxon::UInt n)
{
_n = n;
}
// function operator with the actual workload
maxon::Result<void> operator ()()
{
// 0! and 1! are 1
maxon::UInt factorial = 1;
if (MAXON_LIKELY(_n > 1))
{
factorial = _n;
while (_n > 1)
{
--_n;
factorial *= _n;
}
}
// store result
return SetResult(std::move(factorial));
}
private:
maxon::UInt _n = 0;
};

A job can also implement:

A job has to be enqueued in a queue to be executed (see job queue below):

// This example creates and starts a job that will return a result value.
// create and start job
const maxon::UInt n = 10;
auto job = FactorialJob::Create(n) iferr_return;
job.Enqueue(); // enqueue the job in the current queue and start
// wait and get result
const maxon::UInt factorial = job.GetResult() iferr_return;
DiagnosticOutput("@! = @", n, factorial);

A running job can be cancelled:

// This example cancels the given job and waits for it to finish.
// cancel the given job
job.CancelAndWait();

These observers can be used to react to certain events:

Further utility function are:

Static utility functions are:

Job Group

Jobs can be organized in job groups. These groups are used to execute and wait for multiple jobs simultaneously. The jobs of a group typically belong together. The jobs are executed as efficiently as possible.

The maxon::JobGroupRef members are:

// This example creates a new job group and adds lambda functions to it.
// create group
for (const maxon::Url& file : files)
{
// add lambda function
group.Add(
[file]()
{
CreateFileHash(file) iferr_ignore("Lambda can't handle errors."_s);
}
// enqueue jobs and wait
group.Enqueue();
group.Wait();
// This example creates a new job group and adds newly created jobs to it.
// create group
for (const maxon::Url& file : files)
{
// create and add job
auto job = FileHashJob::Create(file) iferr_return;
group.Add(job) iferr_return;
}
// enqueue jobs and wait
group.Enqueue();
group.Wait();
// This example creates a new job group and adds generic jobs to it.
// create group
for (const maxon::Url& file : files)
{
// add generic job defined by a lambda function
[file]() -> maxon::Result<void>
{
return CreateFileHash(file);
group.Add(job) iferr_return;
}
// enqueue jobs and wait
group.Enqueue();
group.Wait();
// This example creates a new job group and adds an array of jobs to it
// create group
// prepare array of jobs
maxon::BaseArray<FileHashJob> jobs;
jobs.EnsureCapacity(files.GetCount()) iferr_return;
for (const maxon::Url& file : files)
{
// create job
FileHashJob& job = jobs.Append() iferr_return;
// init job
job.SetFile(file) iferr_return;
}
group.Add(jobs) iferr_return;
// enqueue jobs and wait
group.Enqueue();
group.Wait();

Jobs that do belong to a job group can handle sub-jobs:

Queue

Jobs are added to a queue which executes these jobs. A queue provides worker threads and distributes the jobs.

Note
Typically it is not needed to create a custom queue. maxon::JOBQUEUE_CURRENT should be used.

Default job queues are:

It is possible to manually create queues in order to organize job execution.

Note
Functions like maxon::JobInterface::Enqueue() or maxon::JobGroupRef::Enqueue() add the job or jobs to the current job queue if no argument is given.
// This example creates a custom job queue and adds jobs to that queue.
// A job barrier is used to start the queue and wait for the results.
// create a custom job queue
// add new jobs to the custom queue
for (maxon::Int32 i = 0; i < count; ++i)
{
auto job = SimpleJob::Create() iferr_return;
job.Enqueue(queue);
}
DiagnosticOutput("Jobs added...");
// create a JobBarrierRef to wait for the queue to finish
maxon::JobBarrierRef barrier = maxon::JobBarrierInterface::Alloc();
barrier.Enqueue(queue);
barrier.Wait();

Further Reading