107 lines
2.9 KiB
Text
107 lines
2.9 KiB
Text
namespace tf {
|
|
|
|
/** @page RequestCancellation Request Cancellation
|
|
|
|
This chapters discusses how to cancel submitted tasks.
|
|
|
|
@tableofcontents
|
|
|
|
@section CancelARunningTaskflow Cancel Execution of Taskflows
|
|
|
|
When you submit a taskflow to an executor (e.g., tf::Executor::run),
|
|
the executor returns a tf::Future object that will hold the result
|
|
of the execution.
|
|
tf::Future is a derived class from std::future.
|
|
In addition to base methods of std::future,
|
|
you can call tf::Future::cancel to cancel the execution of a running taskflow.
|
|
The following example cancels a submission of a taskflow that contains
|
|
1000 tasks each running one second.
|
|
|
|
@code{.cpp}
|
|
tf::Executor executor;
|
|
tf::Taskflow taskflow;
|
|
|
|
for(int i=0; i<1000; i++) {
|
|
taskflow.emplace([](){
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
});
|
|
}
|
|
|
|
// submit the taskflow
|
|
tf::Future<void> fu = executor.run(taskflow);
|
|
|
|
// request to cancel the above submitted execution
|
|
fu.cancel();
|
|
|
|
// wait until the cancellation completes
|
|
fu.get();
|
|
@endcode
|
|
|
|
@note
|
|
tf::Future::cancel is @em non-deterministic and @em out-of-order.
|
|
|
|
When you request a cancellation, the executor will stop scheduling
|
|
the rest tasks of the taskflow.
|
|
Tasks that are already running will continue to finish,
|
|
but their successor tasks will not be scheduled to run.
|
|
A cancellation is considered complete when all these running tasks finish.
|
|
To wait for a cancellation to complete,
|
|
you may explicitly call @c tf::Future::get.
|
|
|
|
@attention
|
|
It is your responsibility to ensure that the taskflow remains alive before the
|
|
cancellation completes.
|
|
|
|
For instance, the following code results in undefined behavior:
|
|
|
|
@code{.cpp}
|
|
tf::Executor executor;
|
|
{
|
|
tf::Taskflow taskflow;
|
|
|
|
for(int i=0; i<1000; i++) {
|
|
taskflow.emplace([](){});
|
|
}
|
|
|
|
tf::Future fu = executor.run(taskflow);
|
|
|
|
fu.cancel(); // there can still be task running after cancellation
|
|
|
|
} // destroying taskflow here can result in undefined behavior
|
|
@endcode
|
|
|
|
The undefined behavior problem exists because tf::Future::cancel does not
|
|
guarantee an immediate cancellation.
|
|
To fix the problem, call @c get to ensure the cancellation completes
|
|
before the end of the scope destroys the taskflow.
|
|
|
|
@code{.cpp}
|
|
tf::Executor executor;
|
|
{
|
|
tf::Taskflow taskflow;
|
|
|
|
for(int i=0; i<1000; i++) {
|
|
taskflow.emplace([](){});
|
|
}
|
|
|
|
tf::Future fu = executor.run(taskflow);
|
|
|
|
fu.cancel(); // there can still be task running after cancellation
|
|
fu.get(); // waits until the cancellation completes
|
|
}
|
|
@endcode
|
|
|
|
@section UnderstandTheLimitationsOfCancellation Understand the Limitations of Cancellation
|
|
|
|
Canceling the execution of a running taskflow has the following limitations:
|
|
+ Cancellation is non-preemptive. A running task will not be cancelled until it finishes.
|
|
+ Cancelling a taskflow with tasks
|
|
acquiring and/or releasing tf::Semaphore results is currently not supported.
|
|
|
|
We may overcome these limitations in the future releases.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|