Back to Taskflow

Taskflow: A General

docs/classtf_1_1Taskflow.html

4.1.028.3 KB
Original Source

| | Taskflow: A General-purpose Task-parallel Programming System |

Loading...

Searching...

No Matches

Public Member Functions | Friends | List of all members

tf::Taskflow Class Reference

class to create a taskflow object More...

#include <taskflow/core/taskflow.hpp>

Inheritance diagram for tf::Taskflow:

[Embedded content](classtf_1_1Taskflow inherit graph.svg)

[legend]

Collaboration diagram for tf::Taskflow:

[Embedded content](classtf_1_1Taskflow coll graph.svg)

[legend]

|

Public Member Functions

| | | Taskflow (const std::string &name) | | | constructs a taskflow with the given name
| | | | | Taskflow () | | | constructs a taskflow
| | | | | Taskflow (Taskflow &&rhs) | | | constructs a taskflow from a moved taskflow
| | | | Taskflow & | operator= (Taskflow &&rhs) | | | move assignment operator
| | | | | ~Taskflow ()=default | | | default destructor
| | | | void | dump (std::ostream &ostream) const | | | dumps the taskflow to a DOT format through a std::ostream target
| | | | std::string | dump () const | | | dumps the taskflow to a std::string of DOT format
| | | | size_t | num_tasks () const | | | queries the number of tasks in this taskflow
| | | | bool | empty () const | | | queries if this taskflow is empty (has no tasks)
| | | | void | name (const std::string &) | | | assigns a new name to this taskflow
| | | | const std::string & | name () const | | | queries the name of this taskflow
| | | | void | clear () | | | clears the associated task dependency graph
| | | | template<typename V> | | void | for_each_task (V &&visitor) const | | | applies a visitor to each task in this taskflow
| | | | void | remove_dependency (Task from, Task to) | | | removes dependencies that go from task from to task to
| | | | Graph & | graph () | | | returns a reference to the underlying graph object
| | | | Public Member Functions inherited from tf::FlowBuilder | | | FlowBuilder (Graph &graph) | | | constructs a flow builder with a graph
| | | | template<StaticTaskLike C> | | Task | emplace (C &&callable) | | | creates a static task
| | | | template<RuntimeTaskLike C> | | Task | emplace (C &&callable) | | | creates a runtime task
| | | | template<SubflowTaskLike C> | | Task | emplace (C &&callable) | | | creates a dynamic task
| | | | template<ConditionTaskLike C> | | Task | emplace (C &&callable) | | | creates a condition task
| | | | template<MultiConditionTaskLike C> | | Task | emplace (C &&callable) | | | creates a multi-condition task
| | | | template<typename... C>
requires (sizeof...(C) > 1) | | auto | emplace (C &&... callables) | | | creates multiple tasks from a list of callable objects
| | | | void | erase (Task task) | | | removes a task from a taskflow
| | | | template<GraphLike T> | | Task | composed_of (T &object) | | | creates a module task for the target object
| | | | Task | adopt (Graph &&graph) | | | creates a module task from a graph by taking over its ownership
| | | | Task | placeholder () | | | creates a placeholder task
| | | | void | linearize (std::vector< Task > &tasks) | | | adds adjacent dependency links to a linear list of tasks
| | | | void | linearize (std::initializer_list< Task > tasks) | | | adds adjacent dependency links to a linear list of tasks
| | | | template<typename B, typename E, typename C, PartitionerLike P = DefaultPartitioner> | | Task | for_each (B first, E last, C callable, P part=P()) | | | constructs an STL-styled parallel-for task
| | | | template<typename B, typename E, typename S, typename C, PartitionerLike P = DefaultPartitioner> | | Task | for_each_index (B first, E last, S step, C callable, P part=P()) | | | constructs an index-based parallel-for task
| | | | template<IndexRangesLike R, typename C, PartitionerLike P = DefaultPartitioner> | | Task | for_each_by_index (R range, C callable, P part=P()) | | | constructs a parallel-for task over a one- or multi-dimensional index range
| | | | template<typename B, typename E, typename O, typename C, PartitionerLike P = DefaultPartitioner> | | Task | transform (B first1, E last1, O d_first, C c, P part=P()) | | | constructs a parallel-transform task
| | | | template<typename B1, typename E1, typename B2, typename O, typename C, PartitionerLike P = DefaultPartitioner>
requires (!PartitionerLike<std::decay_t<C>>) | | Task | transform (B1 first1, E1 last1, B2 first2, O d_first, C c, P part=P()) | | | constructs a parallel-transform task
| | | | template<typename B, typename E, typename T, typename O, PartitionerLike P = DefaultPartitioner> | | Task | reduce (B first, E last, T &init, O bop, P part=P()) | | | constructs an STL-styled parallel-reduction task
| | | | template<IndexRanges1DLike R, typename T, typename L, typename G, PartitionerLike P = DefaultPartitioner> | | Task | reduce_by_index (R range, T &init, L lop, G gop, P part=P()) | | | constructs an index range-based parallel-reduction task
| | | | template<typename B, typename E, typename T, typename BOP, typename UOP, PartitionerLike P = DefaultPartitioner> | | Task | transform_reduce (B first, E last, T &init, BOP bop, UOP uop, P part=P()) | | | constructs an STL-styled parallel transform-reduce task
| | | | template<typename B1, typename E1, typename B2, typename T, typename BOP_R, typename BOP_T, PartitionerLike P = DefaultPartitioner>
requires (!PartitionerLike<std::decay_t<BOP_T>>) | | Task | transform_reduce (B1 first1, E1 last1, B2 first2, T &init, BOP_R bop_r, BOP_T bop_t, P part=P()) | | | constructs an STL-styled parallel transform-reduce task
| | | | template<typename B, typename E, typename D, typename BOP> | | Task | inclusive_scan (B first, E last, D d_first, BOP bop) | | | creates an STL-styled parallel inclusive-scan task
| | | | template<typename B, typename E, typename D, typename BOP, typename T> | | Task | inclusive_scan (B first, E last, D d_first, BOP bop, T init) | | | creates an STL-styled parallel inclusive-scan task with an initial value
| | | | template<typename B, typename E, typename D, typename T, typename BOP> | | Task | exclusive_scan (B first, E last, D d_first, T init, BOP bop) | | | creates an STL-styled parallel exclusive-scan task
| | | | template<typename B, typename E, typename D, typename BOP, typename UOP> | | Task | transform_inclusive_scan (B first, E last, D d_first, BOP bop, UOP uop) | | | creates an STL-styled parallel transform-inclusive scan task
| | | | template<typename B, typename E, typename D, typename BOP, typename UOP, typename T> | | Task | transform_inclusive_scan (B first, E last, D d_first, BOP bop, UOP uop, T init) | | | creates an STL-styled parallel transform-inclusive scan task
| | | | template<typename B, typename E, typename D, typename T, typename BOP, typename UOP> | | Task | transform_exclusive_scan (B first, E last, D d_first, T init, BOP bop, UOP uop) | | | creates an STL-styled parallel transform-exclusive scan task
| | | | template<typename B, typename E, typename T, typename UOP, PartitionerLike P = DefaultPartitioner> | | Task | find_if (B first, E last, T &result, UOP predicate, P part=P()) | | | constructs a task to perform STL-styled find-if algorithm
| | | | template<typename B, typename E, typename T, typename UOP, PartitionerLike P = DefaultPartitioner> | | Task | find_if_not (B first, E last, T &result, UOP predicate, P part=P()) | | | constructs a task to perform STL-styled find-if-not algorithm
| | | | template<typename B, typename E, typename T, typename C, PartitionerLike P> | | Task | min_element (B first, E last, T &result, C comp, P part) | | | constructs a task to perform STL-styled min-element algorithm
| | | | template<typename B, typename E, typename T, typename C, PartitionerLike P> | | Task | max_element (B first, E last, T &result, C comp, P part) | | | constructs a task to perform STL-styled max-element algorithm
| | | | template<typename B, typename E, typename C> | | Task | sort (B first, E last, C cmp) | | | constructs a dynamic task to perform STL-styled parallel sort
| | | | template<typename B, typename E> | | Task | sort (B first, E last) | | | constructs a dynamic task to perform STL-styled parallel sort using the std::less<T> comparator, where T is the element type
| | | | template<typename B1, typename E1, typename B2, typename E2, typename O> | | Task | merge (B1 first1, E1 last1, B2 first2, E2 last2, O d_first) | | | merges two sorted ranges into a single sorted output using the std::less comparator
| | | | template<typename B1, typename E1, typename B2, typename E2, typename O, typename C> | | Task | merge (B1 first1, E1 last1, B2 first2, E2 last2, O d_first, C cmp) | | | merges two sorted ranges into a single sorted output using a custom comparator
| | | | template<typename B, typename E, typename V, PartitionerLike P = DefaultPartitioner> | | Task | fill (B first, E last, V value, P part=P()) | | | fills a range with a given value in parallel
| | | | template<typename B, std::integral C, typename V, PartitionerLike P = DefaultPartitioner> | | Task | fill_n (B first, C count, V value, P part=P()) | | | fills N elements with a given value in parallel
| | | | template<typename B, typename E, typename G, PartitionerLike P = DefaultPartitioner> | | Task | generate (B first, E last, G gen, P part=P()) | | | generates values into a range in parallel using a callable
| | | | template<typename B, std::integral C, typename G, PartitionerLike P = DefaultPartitioner> | | Task | generate_n (B first, C count, G gen, P part=P()) | | | generates N values into a range in parallel using a callable
| | |

|

Friends

| | class | Topology | | | | class | Executor | | | | class | FlowBuilder | | | | class | Subflow | | |

Detailed Description

class to create a taskflow object

A taskflow manages a task dependency graph where each task represents a callable object (e.g., lambda, std::function) and an edge represents a dependency between two tasks. A task is one of the following types:

  1. static task : the callable constructible from std::function<void()>
  2. subflow task : the callable constructible from std::function<void(tf::Subflow&)>
  3. condition task : the callable constructible from std::function<int()>
  4. multi-condition task: the callable constructible from std::function<tf::SmallVector<int>()>
  5. module task : the task constructed from tf::Taskflow::composed_of std::function<void(tf::Runtime&)>

Each task is a basic computation unit and is run by one worker thread from an executor. The following example creates a simple taskflow graph of four static tasks, A, B, C, and D, where A runs before B and C and D runs after B and C.

tf::Executor executor;

tf::Taskflow taskflow("simple");

tf::Task A = taskflow.emplace({ std::cout << "TaskA\n"; });

tf::Task B = taskflow.emplace({ std::cout << "TaskB\n"; });

tf::Task C = taskflow.emplace({ std::cout << "TaskC\n"; });

tf::Task D = taskflow.emplace({ std::cout << "TaskD\n"; });

A.precede(B, C); // A runs before B and C

D.succeed(B, C); // D runs after B and C

executor.run(taskflow).wait();

tf::Executor

class to create an executor

Definition executor.hpp:62

tf::Executor::run

tf::Future< void > run(Taskflow &taskflow)

runs a taskflow once

tf::Task

class to create a task handle over a taskflow node

Definition task.hpp:569

tf::Task::succeed

Task & succeed(Ts &&... tasks)

adds precedence links from other tasks to this

Definition task.hpp:1266

tf::Task::precede

Task & precede(Ts &&... tasks)

adds precedence links from this to other tasks

Definition task.hpp:1258

tf::Taskflow

class to create a taskflow object

Definition taskflow.hpp:64

The taskflow object itself is NOT thread-safe. You should not modifying the graph while it is running, such as adding new tasks, adding new dependencies, and moving the taskflow to another.

Please refer to Cookbook to learn more about each task type and how to submit a taskflow to an executor.

Constructor & Destructor Documentation

Taskflow() [1/2]

|

| tf::Taskflow::Taskflow | ( | const std::string & | name | ) | |

| inline |

constructs a taskflow with the given name

tf::Taskflow taskflow("My Taskflow");

std::cout << taskflow.name(); // "My Taskflow"

Taskflow() [2/2]

|

| tf::Taskflow::Taskflow | ( | Taskflow && | rhs | ) | |

| inline |

constructs a taskflow from a moved taskflow

Constructing a taskflow taskflow1 from a moved taskflow taskflow2 will migrate the graph of taskflow2 to taskflow1. After the move, taskflow2 will become empty.

tf::Taskflow taskflow1(std::move(taskflow2));

assert(taskflow2.empty());

AttentionYou should avoid moving a taskflow that is currently running on an executor. Doing so results in undefined behavior.

~Taskflow()

|

| tf::Taskflow::~Taskflow | ( | | ) | |

| default |

default destructor

When the destructor is called, all tasks and their associated data (e.g., captured data) will be destroyed. It is your responsibility to ensure all submitted execution of this taskflow have completed before destroying it. For instance, the following code results in undefined behavior since the executor may still be running the taskflow while it is destroyed after the block.

{

tf::Taskflow taskflow;

executor.run(taskflow);

}

To fix the problem, we must wait for the execution to complete before destroying the taskflow.

{

tf::Taskflow taskflow;

executor.run(taskflow).wait();

}

Member Function Documentation

clear()

|

| void tf::Taskflow::clear | ( | | ) | |

| inline |

clears the associated task dependency graph

When you clear a taskflow, all tasks and their associated data (e.g., captured data in task callables) will be destroyed. The behavior of clearing a running taskflow is undefined.

dump() [1/2]

|

| std::string tf::Taskflow::dump | ( | | ) | const |

| inline |

dumps the taskflow to a std::string of DOT format

This method is similar to tf::Taskflow::dump(std::ostream& ostream), but returning a string of the graph in DOT format.

dump() [2/2]

|

| void tf::Taskflow::dump | ( | std::ostream & | ostream | ) | const |

| inline |

dumps the taskflow to a DOT format through a std::ostream target

taskflow.dump(std::cout); // dump the graph to the standard output

std::ofstream ofs("output.dot");

taskflow.dump(ofs); // dump the graph to the file output.dot

For dynamically spawned tasks, such as module tasks, subflow tasks, and GPU tasks, you need to run the taskflow first before you can dump the entire graph. For subflow tasks the subflow must be retained, otherwise it is cleared when joined and the child tasks not shown in the DOT graph.

tf::Task parent = taskflow.emplace([](tf::Subflow sf){

sf.emplace({ std::cout << "child\n"; });

sf.retain(true);

});

taskflow.dump(std::cout); // this dumps only the parent tasks

executor.run(taskflow).wait();

taskflow.dump(std::cout); // this dumps both parent and child tasks

tf::FlowBuilder::emplace

Task emplace(C &&callable)

creates a static task

Definition flow_builder.hpp:1571

tf::Subflow

class to construct a subflow graph from the execution of a dynamic task

Definition flow_builder.hpp:1735

tf::Subflow::retain

void retain(bool flag) noexcept

specifies whether to keep the subflow after it is joined

Definition flow_builder.hpp:1844

tf::Task::dump

void dump(std::ostream &ostream) const

dumps the task through an output stream

Definition task.hpp:1482

empty()

|

| bool tf::Taskflow::empty | ( | | ) | const |

| inline |

queries if this taskflow is empty (has no tasks)

An empty taskflow has no tasks, i.e., the return of tf::Taskflow::num_tasks is 0.

tf::Taskflow taskflow;

assert(taskflow.empty() == true);

taskflow.emplace({});

assert(taskflow.empty() == false);

tf::Taskflow::empty

bool empty() const

queries if this taskflow is empty (has no tasks)

Definition taskflow.hpp:381

for_each_task()

template<typename V>

| void tf::Taskflow::for_each_task | ( | V && | visitor | ) | const |

applies a visitor to each task in this taskflow

A visitor is a callable that takes an argument of type tf::Task and returns nothing. The following example iterates each task in a taskflow and prints its name:

taskflow.for_each_task([](tf::Task task){

std::cout << task.name() << '\n';

});

tf::Task::name

const std::string & name() const

queries the name of the task

Definition task.hpp:1388

graph()

|

| Graph & tf::Taskflow::graph | ( | | ) | |

| inline |

returns a reference to the underlying graph object

A graph object is of type tf::Graph and stores a task dependency graph that can be executed by an tf::Executor.

name() [1/2]

|

| const std::string & tf::Taskflow::name | ( | | ) | const |

| inline |

queries the name of this taskflow

tf::Taskflow taskflow("foo");

assert(taskflow.name() == "foo");

name() [2/2]

|

| void tf::Taskflow::name | ( | const std::string & | name | ) | |

| inline |

assigns a new name to this taskflow

taskflow.name("foo");

assert(taskflow.name() == "foo");

num_tasks()

|

| size_t tf::Taskflow::num_tasks | ( | | ) | const |

| inline |

queries the number of tasks in this taskflow

The number of tasks in this taskflow is defined at the first level of hierarchy. Tasks that are created dynamically, such as those via tf::Subflow, are not counted.

tf::Taskflow taskflow;

auto my_task = taskflow.emplace({});

assert(taskflow.num_tasks() == 1);

// reassign my_task to a subflow of four tasks

my_task.work([](tf::Subflow& sf){

sf.emplace(

{ std::cout << "Task A\n"; },

{ std::cout << "Task B\n"; },

{ std::cout << "Task C\n"; },

{ std::cout << "Task D\n"; }

);

});

// subflow tasks will not be counted

assert(taskflow.num_tasks() == 1);

tf::Taskflow::num_tasks

size_t num_tasks() const

queries the number of tasks in this taskflow

Definition taskflow.hpp:376

operator=()

|

| Taskflow & tf::Taskflow::operator= | ( | Taskflow && | rhs | ) | |

| inline |

move assignment operator

Moving a taskflow taskflow2 to another taskflow taskflow1 will destroy the existing graph of taskflow1 and assign it the graph of taskflow2. After the move, taskflow2 will become empty.

taskflow1 = std::move(taskflow2);

assert(taskflow2.empty());

AttentionYou should avoid moving a taskflow that is currently running on an executor. Doing so results in undefined behavior.

remove_dependency()

|

| void tf::Taskflow::remove_dependency | ( | Task | from, | | | | Task | to ) |

| inline |

removes dependencies that go from task from to task to

Parameters

| from | from task (dependent) | | to | to task (successor) |

Removing the depencency from task from to task to is equivalent to removing to from the succcessor list of from and removing from from the predecessor list of to.

tf::Taskflow taskflow;

auto a = taskflow.placeholder().name("a");

auto b = taskflow.placeholder().name("b");

auto c = taskflow.placeholder().name("c");

auto d = taskflow.placeholder().name("d");

a.precede(b, c, d);

assert(a.num_successors() == 3);

assert(b.num_predecessors() == 1);

assert(c.num_predecessors() == 1);

assert(d.num_predecessors() == 1);

taskflow.remove_dependency(a, b);

assert(a.num_successors() == 2);

assert(b.num_predecessors() == 0);

tf::FlowBuilder::placeholder

Task placeholder()

creates a placeholder task

Definition flow_builder.hpp:1635

tf::Taskflow::remove_dependency

void remove_dependency(Task from, Task to)

removes dependencies that go from task from to task to

Definition taskflow.hpp:409

AttentionFor performance reason, Taskflow does not store the graph using linked lists but vectors with contiguous space. Therefore, removing tasks or dependencies incurs linear time complexity proportional to the size of the graph and the dependency count of a task.


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