Cookbook » Runtime Tasking

Taskflow allows you to interact with the scheduling runtime from the execution context of a runtime task. Runtime tasking is mostly used for designing specialized parallel algorithms that go beyond the default scheduling rules of taskflows.

Create a Runtime Task

A runtime task is a callable that takes a reference to a tf::Runtime object in its argument. A tf::Runtime object is created by the running executor and contains several methods for users to interact with the scheduling runtime. For instance, the following code creates a runtime task to forcefully schedule a conditioned task that would never happens:

tf::Task A, B, C, D;
std::tie(A, B, C, D) = taskflow.emplace(
  [] () { return 0; },
  [&C] (tf::Runtime& rt) {  // C must be captured by reference
    std::cout << "B\n"; 
    rt.schedule(C);
  },
  [] () { std::cout << "C\n"; },
  [] () { std::cout << "D\n"; }
);
A.precede(B, C, D);
executor.run(taskflow).wait();
Taskflow p0x7bc400014030 D p0x7bc400014118 C p0x7bc400014200 B p0x7bc4000142e8 A p0x7bc4000142e8->p0x7bc400014030 2 p0x7bc4000142e8->p0x7bc400014118 1 p0x7bc4000142e8->p0x7bc400014200 0

When the condition task A completes and returns 0, the scheduler moves on to the runtime task B. Under the normal circumstance, tasks C and D will not run because their conditional dependencies never happen. This can be broken by forcefully scheduling C or/and D via a runtime task that resides in the same graph. Here, the runtime task B call tf::Runtime::schedule(tf::Task) to run task C even though the weak dependency between A and C will never happen based on the graph structure itself. As a result, we will see both B and C in the output:

B    # B is a runtime task to schedule C out of its dependency constraint
C

Acquire the Running Executor

You can acquire the reference to the running executor using tf::Runtime::executor(). The running executor of a runtime task is the executor that runs the parent taskflow of that runtime task.

tf::Executor executor;
tf::Taskflow taskflow;
taskflow.emplace([&](tf::Runtime& rt){
  assert(&(rt.executor()) == &executor);
});
executor.run(taskflow).wait();