diff --git a/headers/enduro2d/utils/jobber.hpp b/headers/enduro2d/utils/jobber.hpp index df97a034..edd6f323 100644 --- a/headers/enduro2d/utils/jobber.hpp +++ b/headers/enduro2d/utils/jobber.hpp @@ -7,6 +7,7 @@ #pragma once #include "_utils.hpp" +#include "time.hpp" namespace e2d { @@ -42,6 +43,18 @@ namespace e2d void wait_all() const noexcept; void active_wait_all() noexcept; + + template < typename T, typename TimeTag > + void wait_for(const unit& time_for) const noexcept; + + template < typename T, typename TimeTag > + void wait_until(const unit& time_until) const noexcept; + + template < typename T, typename TimeTag > + void active_wait_for(const unit& time_for) noexcept; + + template < typename T, typename TimeTag > + void active_wait_until(const unit& time_until) noexcept; private: class task; using task_ptr = std::unique_ptr; @@ -123,6 +136,55 @@ namespace e2d return future; } + // + // wait + // + + template < typename T, typename TimeTag > + void jobber::wait_for(const unit& time_for) const noexcept { + if ( time_for.value > T(0) ) { + wait_until( + time::now() + + time_for.template cast_to()); + } + } + + template < typename T, typename TimeTag > + void jobber::wait_until(const unit& time_until) const noexcept { + while ( active_task_count_ ) { + const auto time_now = time::now(); + if ( time_now >= time_until.template cast_to() ) { + break; + } + std::this_thread::yield(); + } + } + + // + // active_wait + // + + template < typename T, typename TimeTag > + void jobber::active_wait_for(const unit& time_for) noexcept { + if ( time_for.value > T(0) ) { + active_wait_until( + time::now() + + time_for.template cast_to()); + } + } + + template < typename T, typename TimeTag > + void jobber::active_wait_until(const unit& time_until) noexcept { + while ( active_task_count_ ) { + const auto time_now = time::now(); + if ( time_now >= time_until.template cast_to() ) { + break; + } + std::unique_lock lock(tasks_mutex_); + process_task_(std::move(lock)); + } + } + // // concrete_task // diff --git a/headers/enduro2d/utils/scheduler.hpp b/headers/enduro2d/utils/scheduler.hpp index 87844e7c..d71d9f93 100644 --- a/headers/enduro2d/utils/scheduler.hpp +++ b/headers/enduro2d/utils/scheduler.hpp @@ -40,10 +40,10 @@ namespace e2d void process_all_tasks() noexcept; template < typename T, typename TimeTag > - void process_all_tasks_for(const unit& time_for) noexcept; + void process_tasks_for(const unit& time_for) noexcept; template < typename T, typename TimeTag > - void process_all_tasks_until(const unit& time_until) noexcept; + void process_tasks_until(const unit& time_until) noexcept; private: class task; using task_ptr = std::unique_ptr; @@ -119,17 +119,21 @@ namespace e2d return future; } + // + // process_all_tasks + // + template < typename T, typename TimeTag > - void scheduler::process_all_tasks_for(const unit& time_for) noexcept { + void scheduler::process_tasks_for(const unit& time_for) noexcept { if ( time_for.value > T(0) ) { - process_all_tasks_until( + process_tasks_until( time::now() + time_for.template cast_to()); } } template < typename T, typename TimeTag > - void scheduler::process_all_tasks_until(const unit& time_until) noexcept { + void scheduler::process_tasks_until(const unit& time_until) noexcept { while ( active_task_count_ ) { const auto time_now = time::now(); if ( time_now >= time_until.template cast_to() ) { diff --git a/untests/sources/untests_utils/jobber.cpp b/untests/sources/untests_utils/jobber.cpp index 75778500..6bba998b 100644 --- a/untests/sources/untests_utils/jobber.cpp +++ b/untests/sources/untests_utils/jobber.cpp @@ -69,6 +69,35 @@ TEST_CASE("jobber") { j.resume(); j.wait_all(); } + { + jobber j(1); + i32 counter = 0; + j.pause(); + for ( std::size_t i = 0; i < 10; ++i ) { + j.async([&counter](){ + ++counter; + std::this_thread::sleep_for(std::chrono::milliseconds(15)); + }); + } + + const auto b = time::now_ms(); + + j.wait_for(make_milliseconds(15)); + REQUIRE(time::now_ms() - b > make_milliseconds(10)); + REQUIRE(counter == 0); + + j.wait_until(time::now_ms() + make_milliseconds(15)); + REQUIRE(time::now_ms() - b > make_milliseconds(20)); + REQUIRE(counter == 0); + + j.active_wait_for(make_milliseconds(60)); + REQUIRE(time::now_ms() - b > make_milliseconds(70)); + REQUIRE(counter > 2); + REQUIRE(counter < 10); + + j.active_wait_until(time::now_s() + make_seconds(1)); + REQUIRE(counter == 10); + } { jobber j(2); jobber g(2); diff --git a/untests/sources/untests_utils/scheduler.cpp b/untests/sources/untests_utils/scheduler.cpp index 106312a3..162b294b 100644 --- a/untests/sources/untests_utils/scheduler.cpp +++ b/untests/sources/untests_utils/scheduler.cpp @@ -29,13 +29,13 @@ TEST_CASE("scheduler") { std::this_thread::sleep_for(std::chrono::milliseconds(15)); }); } - s.process_all_tasks_for(make_milliseconds(-1)); - s.process_all_tasks_for(make_milliseconds(0)); + s.process_tasks_for(make_milliseconds(-1)); + s.process_tasks_for(make_milliseconds(0)); REQUIRE(counter == 0); - s.process_all_tasks_for(make_milliseconds(60)); + s.process_tasks_for(make_milliseconds(60)); REQUIRE(counter > 2); REQUIRE(counter < 10); - s.process_all_tasks_for(make_seconds(1)); + s.process_tasks_for(make_seconds(1)); REQUIRE(counter == 10); } { @@ -47,13 +47,13 @@ TEST_CASE("scheduler") { std::this_thread::sleep_for(std::chrono::milliseconds(15)); }); } - s.process_all_tasks_until(time::now_ms() - make_milliseconds(1)); - s.process_all_tasks_until(time::now_ms()); + s.process_tasks_until(time::now_ms() - make_milliseconds(1)); + s.process_tasks_until(time::now_ms()); REQUIRE(counter == 0); - s.process_all_tasks_until(time::now_ms() + make_milliseconds(60)); + s.process_tasks_until(time::now_ms() + make_milliseconds(60)); REQUIRE(counter > 2); REQUIRE(counter < 10); - s.process_all_tasks_until(time::now_s() + make_seconds(1)); + s.process_tasks_until(time::now_s() + make_seconds(1)); REQUIRE(counter == 10); } {