#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include #include // ---------------------------------------------------------------------------- // Starvation Test // ---------------------------------------------------------------------------- void starvation_test(size_t W) { tf::Taskflow taskflow; tf::Executor executor(W); std::atomic counter{0}; tf::Task prev, curr; // simple linear chain for(size_t l=0; l<100; l++) { curr = taskflow.emplace([&](){ counter.fetch_add(1, std::memory_order_relaxed); }); if(l) { curr.succeed(prev); } prev = curr; } // branches for(size_t b=W/2; b W); tf::Taskflow taskflow; tf::Executor executor(W); std::atomic counter{0}; std::atomic barrier{0}; // all worker must be involved std::mutex mutex; std::unordered_set set; auto [merge, cond, stop] = taskflow.emplace( [&](){ REQUIRE(barrier.load(std::memory_order_relaxed) == B); REQUIRE(counter.load(std::memory_order_relaxed) == (L + B - 1)); REQUIRE(set.size() == W); counter = 0; barrier = 0; set.clear(); }, [n=0]() mutable { return ++n >= 10 ? 1 : 0; }, [&](){ REQUIRE(barrier.load(std::memory_order_relaxed) == 0); REQUIRE(counter.load(std::memory_order_relaxed) == 0); REQUIRE(set.size() == 0); } ); tf::Task prev, curr, second; // linear chain with delay to make workers sleep for(size_t l=0; l W); tf::Taskflow taskflow; tf::Executor executor(W); std::atomic counter{0}; std::atomic barrier{0}; // all worker must be involved std::mutex mutex; std::unordered_set set; taskflow.emplace([&](tf::Subflow& subflow){ auto [merge, cond, stop] = subflow.emplace( [&](){ REQUIRE(barrier.load(std::memory_order_relaxed) == B); REQUIRE(counter.load(std::memory_order_relaxed) == (L + B - 1)); REQUIRE(set.size() == W); counter = 0; barrier = 0; set.clear(); }, [n=0]() mutable { return ++n >= 5 ? 1 : 0; }, [&](){ REQUIRE(barrier.load(std::memory_order_relaxed) == 0); REQUIRE(counter.load(std::memory_order_relaxed) == 0); REQUIRE(set.size() == 0); } ); tf::Task prev, curr, second; // linear chain with delay to make workers sleep for(size_t l=0; l W); tf::Taskflow taskflow, parent; tf::Executor executor(W); std::atomic barrier{0}; // all worker must be involved std::mutex mutex; std::unordered_set set; // fork for(size_t b=0; b stop, count; // all worker must be involved std::mutex mutex; std::unordered_set set; tf::Task parent = taskflow.emplace([&](){ set.clear(); count.store(0, std::memory_order_relaxed); stop.store(false, std::memory_order_relaxed); }).name("root"); tf::Task left, right; for(size_t w=0; w stop, count; // all worker must be involved std::mutex mutex; std::unordered_set set; tf::Task parent = taskflow.emplace([&](){ set.clear(); count.store(0, std::memory_order_relaxed); stop.store(false, std::memory_order_relaxed); }).name("root"); tf::Task pivot; for(size_t w=0; w stop, count{0}, blocked; // all worker must be involved std::mutex mutex; std::unordered_set set; std::vector> G; G.resize(W); // create tasks for(size_t i=0; i counter{0}; // all worker must be involved std::mutex mutex; std::unordered_set set; for(size_t n = 0; n