Frequently used implementation for job with a functor.
Peano's tasking API is a plain class-based implementation of a task system. Many modern APIs such as oneTBB favour a functor-based API. The latter approach add nothing new, as C++ internally breaks down functors into classes with an operator(). In Peano, we mirror this behaviour, i.e. start with a class design and then offer this class on top which allows you to pipe in a functor instead of implementing your run() within a subclass.
Most people using lambdas for this class will define a lambda within a function which catches all relevant data and then pass this lambda into a task. This implies that this lambda object will be destroyed once the spawning routine terminates, even though the task might not have been executed at this point. Therefore, this routine copies the lambda.
The functor is a 1:1 translation of Task's run(). It takes no arguments, and it returns a bool which indicates if this task has to rerun. Returning false signals that this task is done and can be discarded. Returning true signals that the task is done, but the same task has to be re-executed. It is up to the tasking runtime to decide if it will re-execute immediately again or at a later point.
A typical usage looks similar to
[=,this]()->bool {
...
return false;
}
);
newTask,
myNumber
);
Frequently used implementation for job with a functor.
Abstract super class for a job.
static constexpr int DontFuse
static constexpr int DefaultPriority
const std::set< TaskNumber > NoInDependencies
void spawnTask(Task *task, const std::set< TaskNumber > &inDependencies=tarch::multicore::NoInDependencies, const TaskNumber &taskNumber=tarch::multicore::NoOutDependencies)
Spawns a single task in a non-blocking fashion.
Definition at line 211 of file Task.h.
tarch::multicore::TaskWithCopyOfFunctor::TaskWithCopyOfFunctor |
( |
int | taskType, |
|
|
int | priority, |
|
|
const std::function< void()> & | taskFunctor ) |
Create new task from a functor.
This is the standard version of a task that should be used with a functor. Obviously, you can use the version without the copying, but if and only if you can ensure that the functor remains valid even once you leave the surrounding scope. This version copies the functor and hence is fine even if the functor had been created (via auto) directly before we construct the task. However, we implicitly assume that the functor's variables all remain available, too, i.e. we'd expect in most cases that the functor catches all surrounding variables through copying.
Tasks capturing external data
If tasks capture and alter external data, constructing them through a functor that's copied doesn't work, as C++ implicitly assumes that this functor has to be const. Therefore, you manually have to set the functor to mutuable. Here is an example from the multigrid extension:
auto invertMatrixFunctor = [inverseOperator, marker, OperatorSize]() mutable -> void {
std::memcpy(
...
);
};
Fusion
You can have functor tasks with generic fusion. For this, simply pass in a proper unique task type, so we can distinguish tasks from each other. This is best done through a factor method as explained in the superclass.
taskType,
[=](...) -> void {
...
}
);
int getTaskType(const std::string &className)
Get unique number (id) for task.
- Parameters
-
taskType | See superclass documentation |
priority | See superclass documentation |
taskFunctor | Functor that's then internally copied. Functor returns indicator if task has to rerun. See class documentation. |
Definition at line 55 of file Task.cpp.