Class task

Class Documentation

class concore::v1::task

A task. Core abstraction for representing an independent unit of work.

A task can be enqueued into an executor and executed at a later time. That is, this represents work that can be scheduled.

Tasks have move-only semantics, and disable copy semantics. Also, the library prefers to move tasks around instead of using shared references to the task. That means that, after construction and initialization, once passed to an executor, the task cannot be modified.

It is assumed that a task can only be executed once.

Ensuring correctness when working with tasks

Within the independent unit of work definition, the word independent is crucial. It is the one that guarantees thread-safety of the applications relying on tasks to represent concurrency.

A task needs to be independent, meaning that it must not be run in parallel with other tasks that touch the same data (and one of them is writing). In other words, it enforces no data races, and no corruptions (in this context data races have the negative effect and they represent undefined behavior).

Please note that this does not say that there can’t be two tasks that touch the same data (and one of them is writing). It says that if we have such case we need to ensure that these tasks are not running in parallel. In other words, one need to apply constraints on these tasks to ensure that they re not run in parallel.

If constraints are added on the tasks ensuring that there are no two conflicting tasks that run in parallel, then we can achieve concurrency without data races.

At the level of task object, there is no explicit way of adding constraints on the tasks. The constraints can be added on top of tasks. See chained_task and serializer.

task_function and task_group

A task is essentially a pair of a task_function an a task_group. The task_function part offers storage for the work associated with the task. The task_group part offers a way of controlling the task execution.

One or most tasks can belong to a task_group. To add a task to an existing task_group pass the task_group object to the constructor of the task object. By using a task_group the user can tell the system to cancel the execution of all the tasks that belong to the task_group. It can also implement logic that depends on the the task_group having no tasks attached to it.

See

task_function, task_group, chained_task, serializer

Public Functions

task() = default

Default constructor.

Brings the task into a valid state. The task has no action to be executed, and does not belong to any task group.

template<typename T>
task(T ftor)

Constructs a new task given a functor.

When the task will be executed, the given functor will be called. This typically happens on a different thread than this constructor is called.

Parameters
  • ftor: The functor to be called when executing task.

Template Parameters
  • T: The type of the functor. Must be compatible with task_function.

To be assumed that the functor will be called at a later time. All the resources needed by the functor must be valid at that time.

template<typename T>
task(T ftor, task_group grp)

Constructs a new task given a functor and a task group.

When the task will be executed, the given functor will be called. This typically happens on a different thread than this constructor is called.

Parameters
  • ftor: The functor to be called when executing task.

  • grp: The task group to place the task in the group.

Template Parameters
  • T: The type of the functor. Must be compatible with task_function.

To be assumed that the functor will be called at a later time. All the resources needed by the functor must be valid at that time.

Through the given group one can cancel the execution of the task, and check (indirectly) when the task is complete.

After a call to this constructor, the group becomes “active”. Calling task_group::is_active() will return true.

See

get_task_group()

template<typename T>
task &operator=(T ftor)

Assignment operator from a functor.

This can be used to change the task function inside the task.

Return

The result of the assignment

Parameters
  • ftor: The functor to be called when executing task.

Template Parameters
  • T: The type of the functor. Must be compatible with task_function.

~task()

Destructor.

If the task belongs to the group, the group will contain one less active task. If this was the last task registered in the group, after this call, calling task_group::is_active() will yield false.

task(task&&) = default

Move constructor.

task &operator=(task&&) = default

Move operator.

task(const task&) = delete

Copy constructor is DISABLED.

task &operator=(const task&) = delete

Copy assignment operator is DISABLED.

void swap(task &other)

Swap the content of the task with another task.

Parameters
  • other: The other task

operator bool() const noexcept

Bool conversion operator.

Indicates if a valid functor is set into the tasks, i.e., if there is anything to be executed.

void operator()()

Function call operator; performs the action stored in the task.

This is called by the execution engine whenever the task is ready to be executed. It will call the functor stored in the task.

The functor can throw, and the execution system is responsible for catching the exception and ensuring its properly propagated to the user.

This is typically called after some time has passed since task creation. The user must ensure that the functor stored in the task is safe to be executed at that point.

const task_group &get_task_group() const

Gets the task group.

This allows the users to consult the task group associated with the task and change it.

Return

The group associated with this task.