tf::Runtime
tf::Subflow
taskflow/core/graph.hpp
class friend class Executor Executor Executor
class friend class FlowBuilder FlowBuilder FlowBuilder
Executor & Executor& tf::Runtime::_executor _executor
Worker & Worker& tf::Runtime::_worker _worker
Node * Node* tf::Runtime::_parent _parent
tf::Runtime::~Runtime
()
~Runtime

destroys the runtime object

Issues a tf::Runtime::corun_all to finish all spawned asynchronous tasks and then destroys the runtime object.

Executor & Executor & tf::Runtime::executor () 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

acquire a reference to the underlying worker

void void tf::Runtime::schedule (Task task) 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 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 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 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 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 F
void void tf::Runtime::silent_async_unchecked (F &&f) silent_async_unchecked F && f

similar to tf::Runtime::silent_async but the caller must be the worker of the runtime

F

callable type

f

callable

The method bypass the check of the caller worker from the executor and thus can only called by the worker of this runtime.

    taskflow.emplace([&](tf::Runtime&rt){
    //runningbytheworkerofthisruntime
    rt.silent_async_unchecked([](){});
    rt.corun_all();
    });

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

similar to tf::Runtime::silent_async but the caller must be the worker of the runtime

F

callable type

P

task parameters type

params

task parameters

f

callable

The method bypass the check of the caller worker from the executor and thus can only called by the worker of this runtime.

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

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

co-runs the given target and waits until it completes

A target can be one of the following forms:

- a subflow task to spawn a subflow or

- a composable graph object with `tf::Graph& T::graph()` defined

    //co-runasubflowandwaituntilalltaskscomplete
    taskflow.emplace([](tf::Runtime&rt){
    rt.corun([](tf::Subflow&sf){
    tf::TaskA=sf.emplace([](){});
    tf::TaskB=sf.emplace([](){});
    });
    });

    //co-runataskflowandwaituntilalltaskscomplete
    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.

Only the worker of this tf::Runtime can issue corun.

typename P
void void tf::Runtime::corun_until (P &&predicate) corun_until P && predicate

keeps running the work-stealing loop until the predicate becomes true

P

predicate type

predicate

a boolean predicate to indicate when to stop the loop

The method keeps the caller worker running in the work-stealing loop until the stop predicate becomes true.

Only the worker of this tf::Runtime can issue corun.

void void tf::Runtime::corun_all () 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);
    });

Only the worker of this tf::Runtime can issue tf::Runtime::corun_all.

typename... S S
std::enable_if_t< all_same_v< Semaphore, std::decay_t< S >... >, void > * nullptr
void void tf::Runtime::acquire (S &&... semaphores) acquire S &&... semaphores

acquires the given semaphores with a deadlock avoidance algorithm

S

semaphore type (tf::Semaphore)

semaphores

semaphores

Coruns this worker until acquiring all the semaphores.

    tf::Semaphoresemaphore(1);
    tf::Executorexecutor;

    //onlyoneworkerwillenterthe"critical_section"atanytime
    for(size_ti=0;i<100;i++){
    executor.async([&](tf::Runtime&rt){
    rt.acquire(semaphore);
    critical_section();
    rt.release(semaphore);
    });
    }

typename I
std::enable_if_t< std::is_same_v< deref_t< I >, Semaphore >, void > * nullptr
void void tf::Runtime::acquire (I first, I last) acquire I first I last

acquires the given range of semaphores with a deadlock avoidance algorithm

I

iterator type

first

iterator to the beginning (inclusive)

last

iterator to the end (exclusive)

Coruns this worker until acquiring all the semaphores.

    std::list<tf::Semaphore>semaphores;
    semaphores.emplace_back(1);
    semaphores.emplace_back(1);
    autofirst=semaphores.begin();
    autolast=semaphores.end();
    tf::Executorexecutor;

    //onlyoneworkerwillenterthe"critical_section"atanytime
    for(size_ti=0;i<100;i++){
    executor.async([&](tf::Runtime&rt){
    rt.acquire(first,last);
    critical_section();
    rt.release(first,last);
    });
    }

typename... S S
std::enable_if_t< all_same_v< Semaphore, std::decay_t< S >... >, void > * nullptr
void void tf::Runtime::release (S &&... semaphores) release S &&... semaphores

releases the given semaphores

S

semaphore type (tf::Semaphore)

semaphores

semaphores

Releases the given semaphores.

    tf::Semaphoresemaphore(1);
    tf::Executorexecutor;

    //onlyoneworkerwillenterthe"critical_section"atanytime
    for(size_ti=0;i<100;i++){
    executor.async([&](tf::Runtime&rt){
    rt.acquire(semaphore);
    critical_section();
    rt.release(semaphore);
    });
    }

typename I
std::enable_if_t< std::is_same_v< deref_t< I >, Semaphore >, void > * nullptr
void void tf::Runtime::release (I first, I last) release I first I last

releases the given range of semaphores

I

iterator type

first

iterator to the beginning (inclusive)

last

iterator to the end (exclusive)

Releases the given range of semaphores.

    std::list<tf::Semaphore>semaphores;
    semaphores.emplace_back(1);
    semaphores.emplace_back(1);
    autofirst=semaphores.begin();
    autolast=semaphores.end();
    tf::Executorexecutor;

    //onlyoneworkerwillenterthe"critical_section"atanytime
    for(size_ti=0;i<100;i++){
    executor.async([&](tf::Runtime&rt){
    rt.acquire(first,last);
    critical_section();
    rt.release(first,last);
    });
    }

tf::Runtime::Runtime
(Executor &, Worker &, Node *)
Runtime
Executor & e
Worker & w
Node * p
typename P
typename F
auto auto tf::Runtime::_async (Worker &w, P &&params, F &&f) _async Worker & w P && params F && f
typename P
typename F
void void tf::Runtime::_silent_async (Worker &w, P &&params, F &&f) _silent_async Worker & w P && params F && f

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
tf::Subflow
- tf::Runtime
  _async
- tf::Runtime
  _executor
- tf::Runtime
  _parent
- tf::Runtime
  _silent_async
- tf::Runtime
  _worker
- tf::Runtime
  acquire
- tf::Runtime
  acquire
- tf::Runtime
  async
- tf::Runtime
  async
- tf::Runtime
  corun
- tf::Runtime
  corun_all
- tf::Runtime
  corun_until
- tf::Runtime
  Executor
- tf::Runtime
  executor
- tf::Runtime
  FlowBuilder
- tf::Runtime
  release
- tf::Runtime
  release
- tf::Runtime
  Runtime
- tf::Runtime
  schedule
- tf::Runtime
  silent_async
- tf::Runtime
  silent_async
- tf::Runtime
  silent_async_unchecked
- tf::Runtime
  silent_async_unchecked
- tf::Runtime
  worker
- tf::Runtime
  ~Runtime