/// /// a continuation task for recursive parallelism /// /// \note @c derived_task must satisfy the following concept: /// \code /// derived_task { /// void continuation(); /// bool splittable(); /// bool serial_execution(); /// tbb::task_list split(); /// }; /// \endcode template struct continuation_task : tbb::task { continuation_task() noexcept : is_continuation(false) {} tbb::task*execute() { tbb::task*next = nullptr; if(is_continuation) static_cast(this)->continuation(); else if((static_cast(this)->splittable() && is_stolen_task()) || !static_cast(this)->serial_execution()) { tbb::task_list sub_tasks = static_cast(this)->split(); recycle_as_continuation(); is_continuation = true; set_ref_count(size(sub_tasks)); // <-- size of task_list next = &(list.pop_front()); spawn(list); } return next; } private: bool is_continuation; }; /// usage example struct my_task : continuation_task { data_type my_data; my_task(my_data const&_data) : my_data(_data) {} void continuation() { my_data.finish(); } bool serial_execution() { if(my_data.need_to_split()) return false; my_data.execute(); return true; } tbb::task_list split() { tbb::task_list list; for(auto sub : my_data) list.push_back(*new(allocate_child() my_task(my_data.sub_task(sub)))); return list; } }; tbb::task::spawn_root_and_wait(*new(tbb::task::allocate_root()) my_task(some_data));