tf::Runtime
taskflow/core/runtime.hpp
class friend class Executor Executor tf::Runtime::Executor Executor
class friend class FlowBuilder FlowBuilder tf::Runtime::FlowBuilder FlowBuilder
class friend class PreemptionGuard PreemptionGuard tf::Runtime::PreemptionGuard PreemptionGuard
class friend class Algorithm Algorithm tf::Runtime::Algorithm Algorithm
Executor & Executor& tf::Runtime::_executor _executor tf::Runtime::_executor
Worker & Worker& tf::Runtime::_worker _worker tf::Runtime::_worker
Node * Node* tf::Runtime::_parent _parent tf::Runtime::_parent
bool bool tf::Runtime::_preempted _preempted tf::Runtime::_preempted {false}
Executor & Executor & tf::Runtime::executor () executor tf::Runtime::executor

obtains the running executor

The running executor of a runtime task is the executor that runs the parent taskflow of that runtime task.

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

Worker & Worker & tf::Runtime::worker () worker tf::Runtime::worker

acquire a reference to the underlying worker

void void tf::Runtime::schedule (Task task) schedule tf::Runtime::schedule Task task

schedules an active task immediately to the worker's queue

task

the given active task to schedule immediately

This member function immediately schedules an active task to the task queue of the associated worker in the runtime task. An active task is a task in a running taskflow. The task may or may not be running, and scheduling that task will immediately put the task into the task queue of the worker that is running the runtime task. Consider the following example:

    tf::TaskA,B,C,D;
    std::tie(A,B,C,D)=taskflow.emplace(
    [](){return0;},
    [&C](tf::Runtime&rt){//Cmustbecapturedbyreference
    std::cout<<"B\n";
    rt.schedule(C);
    },
    [](){std::cout<<"C\n";},
    [](){std::cout<<"D\n";}
    );
    A.precede(B,C,D);
    executor.run(taskflow).wait();

The executor will first run the condition task `A` which returns `0` to inform the scheduler to go to the runtime task `B`. During the execution of `B`, it directly schedules task `C` without going through the normal taskflow graph scheduling process. At this moment, task `C` is active because its parent taskflow is running. When the taskflow finishes, we will see both `B` and `C` in the output.

typename F
auto auto tf::Runtime::async (F &&f) async tf::Runtime::async F && f

runs the given callable asynchronously

F

callable type

f

callable object

The method creates an asynchronous task to launch the given function on the given arguments. The difference to tf::Executor::async is that the created asynchronous task pertains to the runtime object. Applications can explicitly issue tf::Runtime::corun_all to wait for all spawned asynchronous tasks to finish. For example:

    std::atomic<int>counter(0);
    taskflow.emplace([&](tf::Runtime&rt){
    autofu1=rt.async([&](){counter++;});
    autofu2=rt.async([&](){counter++;});
    fu1.get();
    fu2.get();
    assert(counter==2);

    //spawn100asynchronoustasksfromtheworkeroftheruntime
    for(inti=0;i<100;i++){
    rt.async([&](){counter++;});
    }

    //waitforthe100asynchronoustaskstofinish
    rt.corun_all();
    assert(counter==102);
    });

This method is thread-safe and can be called by multiple workers that hold the reference to the runtime. For example, the code below spawns 100 tasks from the worker of a runtime, and each of the 100 tasks spawns another task that will be run by another worker.

    std::atomic<int>counter(0);
    taskflow.emplace([&](tf::Runtime&rt){
    //workeroftheruntimespawns100taskseachspawninganothertask
    //thatwillberunbyanotherworker
    for(inti=0;i<100;i++){
    rt.async([&](){
    counter++;
    rt.async([](){counter++;});
    });
    }

    //waitforthe200asynchronoustaskstofinish
    rt.corun_all();
    assert(counter==200);
    });

typename P
typename F
auto auto tf::Runtime::async (P &&params, F &&f) async tf::Runtime::async P && params F && f

runs the given callable asynchronously

F

callable type

P

task parameters type

params

task parameters

f

callable

    taskflow.emplace([&](tf::Runtime&rt){
    autofuture=rt.async("mytask",[](){});
    future.get();
    });

typename F
void void tf::Runtime::silent_async (F &&f) silent_async tf::Runtime::silent_async F && f

runs the given function asynchronously without returning any future object

F

callable type

f

callable

This member function is more efficient than tf::Runtime::async and is encouraged to use when there is no data returned.

    std::atomic<int>counter(0);
    taskflow.emplace([&](tf::Runtime&rt){
    for(inti=0;i<100;i++){
    rt.silent_async([&](){counter++;});
    }
    rt.corun_all();
    assert(counter==100);
    });

This member function is thread-safe.

typename P
typename F
void void tf::Runtime::silent_async (P &&params, F &&f) silent_async tf::Runtime::silent_async P && params F && f

runs the given function asynchronously without returning any future object

F

callable type

params

task parameters

f

callable

    taskflow.emplace([&](tf::Runtime&rt){
    rt.silent_async("mytask",[](){});
    rt.corun_all();
    });

typename T
void void tf::Runtime::corun (T &&target) corun tf::Runtime::corun T && target

co-runs the given target and waits until it completes

A corunnable target must have `tf::Graph& T::graph()` defined.

co-run a taskflow and wait until all tasks complete

    tf::Taskflowtaskflow1,taskflow2;
    taskflow1.emplace([](){std::cout<<"runningtaskflow1\n";});
    taskflow2.emplace([&](tf::Runtime&rt){
    std::cout<<"runningtaskflow2\n";
    rt.corun(taskflow1);
    });
    executor.run(taskflow2).wait();

Although tf::Runtime::corun blocks until the operation completes, the caller thread (worker) is not blocked (e.g., sleeping or holding any lock). Instead, the caller thread joins the work-stealing loop of the executor and returns when all tasks in the target completes.

The method is not thread-safe as it modifies the anchor state of the node for exception handling.

void void tf::Runtime::corun_all () corun_all tf::Runtime::corun_all

corun all asynchronous tasks spawned by this runtime with other workers

Coruns all asynchronous tasks (tf::Runtime::async, tf::Runtime::silent_async) with other workers until all those asynchronous tasks finish.

    std::atomic<size_t>counter{0};
    taskflow.emplace([&](tf::Runtime&rt){
    //spawn100asynctasksandwait
    for(inti=0;i<100;i++){
    rt.silent_async([&](){counter++;});
    }
    rt.corun_all();
    assert(counter==100);

    //spawnanother100asynctasksandwait
    for(inti=0;i<100;i++){
    rt.silent_async([&](){counter++;});
    }
    rt.corun_all();
    assert(counter==200);
    });

The method is not thread-safe as it modifies the anchor state of the node for exception handling.

tf::Runtime::Runtime
(Executor &, Worker &, Node *)
Runtime
tf::Runtime::Runtime
Executor & executor
Worker & worker
Node * parent

class to include a runtime object in a task

A runtime object allows users to interact with the scheduling runtime inside a task, such as scheduling an active task, spawning a subflow, and so on.

    tf::TaskA,B,C,D;
    std::tie(A,B,C,D)=taskflow.emplace(
    [](){return0;},
    [&C](tf::Runtime&rt){//Cmustbecapturedbyreference
    std::cout<<"B\n";
    rt.schedule(C);
    },
    [](){std::cout<<"C\n";},
    [](){std::cout<<"D\n";}
    );
    A.precede(B,C,D);
    executor.run(taskflow).wait();

A runtime object is associated with the worker and the executor that runs the task.

- tf::Runtime
  _executor
- tf::Runtime
  _parent
- tf::Runtime
  _preempted
- tf::Runtime
  _worker
- tf::Runtime
  Algorithm
- tf::Runtime
  async
- tf::Runtime
  async
- tf::Runtime
  corun
- tf::Runtime
  corun_all
- tf::Runtime
  Executor
- tf::Runtime
  executor
- tf::Runtime
  FlowBuilder
- tf::Runtime
  PreemptionGuard
- tf::Runtime
  Runtime
- tf::Runtime
  schedule
- tf::Runtime
  silent_async
- tf::Runtime
  silent_async
- tf::Runtime
  worker