从运行的Taskflow中捕捉异常
当Task抛出异常时,执行器将以tf::Future句柄引用的共享状态存储该异常。
#include <taskflow/taskflow.hpp>
void print_str(char const* str) {
std::cout << str << std::endl;
}
int main() {
tf::Executor executor;
tf::Taskflow taskflow;
// task抛出一个异常
taskflow.emplace([](){ throw std::runtime_error("exception"); });
// Task抛出的异常将会存入future中
tf::Future<void> future = executor.run(taskflow);
try {
future.get(); // 并在get() 获取
}
catch(const std::runtime_error& e) {
std::cerr << e.what() << std::endl;
}
// 上面逻辑的简化版
// try {
// executor.run(taskflow).get();
// }
// catch(const std::runtime_error& e) {
// std::cerr << e.what() << std::endl;
// }
}
由于tf::Future是从std::future派生的,它继承了C++标准定义的所有异常处理行为。
异常将会自动取消Taskflow的执行。所有依赖该异常Task的后续任务将无法运行。
#include <taskflow/taskflow.hpp>
void print_str(char const* str) {
std::cout << str << std::endl;
}
int main() {
tf::Executor executor;
tf::Taskflow taskflow;
tf::Task A = taskflow.emplace([](){ throw std::runtime_error("exception on A"); });
tf::Task B = taskflow.emplace([](){ std::cout << "Task B\n"; });
A.precede(B);
try {
executor.run(taskflow).get();
}
catch(const std::runtime_error& e) {
std::cerr << e.what() << std::endl;
}
}
当A抛出异常时,执行者将取消任务流的执行,停止在A之后运行的每个任务。在这种情况下,B不会运行。
当并发任务中,多个Task抛出异常,Taskflow只会存储一个异常,并忽略其他异常:
#include <taskflow/taskflow.hpp>
int main() {
tf::Executor executor;
tf::Taskflow taskflow;
auto [A, B, C, D] = taskflow.emplace(
[]() { std::cout << "TaskA\n"; },
[]() {
std::cout << "TaskB\n";
throw std::runtime_error("Exception on Task B");
},
[]() {
std::cout << "TaskC\n";
throw std::runtime_error("Exception on Task C");
},
[]() { std::cout << "TaskD will not be printed due to exception\n"; }
);
A.precede(B, C); // A runs before B and C
D.succeed(B, C); // D runs after B and C
try {
executor.run(taskflow).get();
}
catch(const std::runtime_error& e) {
// catched either B's or C's exception
std::cout << e.what() << std::endl;
}
}
同样,异步Task也依靠future传播异常:
tf::Executor executor;
auto fu = executor.async([](){ throw std::runtime_error("exception"); });
try {
fu.get();
}
catch(const std::runtime_error& e) {
std::cerr << e.what() << std::endl;
}
tf::Executor::silent_async 不会返回future,所以其异常会被传播到其父Task,或者忽略(没有父Task时):
tf::Taskflow taskflow;
tf::Executor executor;
// execption will be silently ignored
executor.silent_async([](){ throw std::runtime_error("exception"); });
// exception will be propagated to the parent tf::Runtime task and then its Taskflow
taskflow.emplace([&](tf::Runtime& rt){
rt.silent_async([](){ throw std::runtime_error("exception"); });
});
try {
taskflow.get();
}
catch(const std::runtime_error& re) {
std::cout << re.what() << std::endl;
}
对于tf::Executor::corun 或者 tf::Runtime::corun,会直接抛出异常,如果tf::Runtime::corun没有捕获异常,它将被传播到其父task。