diff --git a/Concurrency/BestEffortUpdater.cpp b/Concurrency/BestEffortUpdater.cpp index 99f706a1c..551730f0b 100644 --- a/Concurrency/BestEffortUpdater.cpp +++ b/Concurrency/BestEffortUpdater.cpp @@ -18,21 +18,24 @@ void BestEffortUpdater::update() { async_task_queue_.enqueue([this]() { // Get time now using the highest-resolution clock provided by the implementation, and determine // the duration since the last time this section was entered. - std::chrono::time_point now = std::chrono::high_resolution_clock::now(); - auto elapsed = now - previous_time_point_; + const std::chrono::time_point now = std::chrono::high_resolution_clock::now(); + const auto elapsed = now - previous_time_point_; previous_time_point_ = now; if(has_previous_time_point_) { // If the duration is valid, convert it to integer cycles, maintaining a rolling error and call the delegate - // if there is one. - int64_t duration = std::chrono::duration_cast(elapsed).count(); - double cycles = ((static_cast(duration) * clock_rate_) / 1e9) + error_; - error_ = fmod(cycles, 1.0); + // if there is one. Proceed only if the number of cycles is positive, and cap it to the per-second maximum — + // it's possible this is an adjustable clock so be ready to swallow unexpected adjustments. + const int64_t duration = std::chrono::duration_cast(elapsed).count(); + if(duration > 0) { + double cycles = ((static_cast(duration) * clock_rate_) / 1e9) + error_; + error_ = fmod(cycles, 1.0); - if(delegate_) { - delegate_->update(this, (int)cycles, has_skipped_); + if(delegate_) { + delegate_->update(this, static_cast(std::min(cycles, clock_rate_)), has_skipped_); + } + has_skipped_ = false; } - has_skipped_ = false; } else { has_previous_time_point_ = true; } @@ -51,13 +54,13 @@ void BestEffortUpdater::flush() { async_task_queue_.flush(); } -void BestEffortUpdater::set_delegate(Delegate *delegate) { +void BestEffortUpdater::set_delegate(Delegate *const delegate) { async_task_queue_.enqueue([this, delegate]() { delegate_ = delegate; }); } -void BestEffortUpdater::set_clock_rate(double clock_rate) { +void BestEffortUpdater::set_clock_rate(const double clock_rate) { async_task_queue_.enqueue([this, clock_rate]() { this->clock_rate_ = clock_rate; });