Skip to content

Commit

Permalink
Makes task_timer generic (#897)
Browse files Browse the repository at this point in the history
* make task_timer tick length configurable
---------

Co-authored-by: Gulliver <[email protected]>
  • Loading branch information
StefanoPetrilli and gittiver authored Sep 29, 2024
1 parent d901e27 commit b8ddff6
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 40 deletions.
90 changes: 56 additions & 34 deletions include/crow/task_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ namespace crow
namespace detail
{

/// A class for scheduling functions to be called after a specific amount of ticks. A tick is equal to 1 second.
/// A class for scheduling functions to be called after a specific
/// amount of ticks. Ther tick length can be handed over in constructor,
/// the default tick length is equal to 1 second.
class task_timer
{
public:
Expand All @@ -39,66 +41,82 @@ namespace crow
private:
using clock_type = std::chrono::steady_clock;
using time_type = clock_type::time_point;

public:
task_timer(asio::io_service& io_service):
io_service_(io_service), timer_(io_service_)
task_timer(asio::io_service& io_service,
const std::chrono::milliseconds tick_length =
std::chrono::seconds(1)) :
io_service_(io_service), timer_(io_service_),
tick_length_ms_(tick_length)
{
timer_.expires_after(std::chrono::seconds(1));
timer_.expires_after(tick_length_ms_);
timer_.async_wait(
std::bind(&task_timer::tick_handler, this, std::placeholders::_1));
std::bind(&task_timer::tick_handler, this,
std::placeholders::_1));
}

~task_timer() { timer_.cancel(); }

/// Cancel the scheduling of the given task
///
/// \param identifier_type task identifier of the task to cancel.
void cancel(identifier_type id)
{
tasks_.erase(id);
CROW_LOG_DEBUG << "task_timer cancelled: " << this << ' ' << id;
CROW_LOG_DEBUG << "task_timer task cancelled: " << this << ' ' << id;
}

/// Schedule the given task to be executed after the default amount of ticks.
/// Schedule the given task to be executed after the default amount
/// of ticks.

///
/// \return identifier_type Used to cancel the thread.
/// It is not bound to this task_timer instance and in some cases could lead to
/// undefined behavior if used with other task_timer objects or after the task
/// has been successfully executed.
/// It is not bound to this task_timer instance and in some cases
/// could lead to undefined behavior if used with other task_timer
/// objects or after the task has been successfully executed.
identifier_type schedule(const task_type& task)
{
tasks_.insert(
{++highest_id_,
{clock_type::now() + std::chrono::seconds(get_default_timeout()),
task}});
CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' << highest_id_;
return highest_id_;
return schedule(task, get_default_timeout());
}

/// Schedule the given task to be executed after the given time.

///
/// \param timeout The amount of ticks (seconds) to wait before execution.
/// \param timeout The amount of ticks to wait before execution.
///
/// \return identifier_type Used to cancel the thread.
/// It is not bound to this task_timer instance and in some cases could lead to
/// undefined behavior if used with other task_timer objects or after the task
/// has been successfully executed.
identifier_type schedule(const task_type& task, std::uint8_t timeout)
/// It is not bound to this task_timer instance and in some cases
/// could lead to undefined behavior if used with other task_timer
/// objects or after the task has been successfully executed.
identifier_type schedule(const task_type& task, uint8_t timeout)
{
tasks_.insert({++highest_id_,
{clock_type::now() + std::chrono::seconds(timeout), task}});
CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' << highest_id_;
{clock_type::now() + (timeout * tick_length_ms_),
task}});
CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' <<
highest_id_;
return highest_id_;
}

/// Set the default timeout for this task_timer instance. (Default: 5)
/// Set the default timeout for this task_timer instance.
/// (Default: 5)

///
/// \param timeout The amount of ticks (seconds) to wait before execution.
void set_default_timeout(std::uint8_t timeout) { default_timeout_ = timeout; }
/// \param timeout The amount of ticks to wait before
/// execution.
/// For tick length \see tick_length_ms_
void set_default_timeout(uint8_t timeout) {
default_timeout_ = timeout;
}

/// Get the default timeout. (Default: 5)
std::uint8_t get_default_timeout() const { return default_timeout_; }
uint8_t get_default_timeout() const {
return default_timeout_;
}

/// returns the length of one tick.
std::chrono::milliseconds get_tick_length() const {
return tick_length_ms_;
}

private:
void process_tasks()
Expand All @@ -112,14 +130,16 @@ namespace crow
{
(task.second.second)();
finished_tasks.push_back(task.first);
CROW_LOG_DEBUG << "task_timer called: " << this << ' ' << task.first;
CROW_LOG_DEBUG << "task_timer called: " << this <<
' ' << task.first;
}
}

for (const auto& task : finished_tasks)
tasks_.erase(task);

// If no task is currently scheduled, reset the issued ids back to 0.
// If no task is currently scheduled, reset the issued ids back
// to 0.
if (tasks_.empty()) highest_id_ = 0;
}

Expand All @@ -129,20 +149,22 @@ namespace crow

process_tasks();

timer_.expires_after(std::chrono::seconds(1));
timer_.expires_after(tick_length_ms_);
timer_.async_wait(
std::bind(&task_timer::tick_handler, this, std::placeholders::_1));
}

private:
std::uint8_t default_timeout_{5};
asio::io_service& io_service_;
asio::basic_waitable_timer<clock_type> timer_;
std::map<identifier_type, std::pair<time_type, task_type>> tasks_;

// A continuosly increasing number to be issued to threads to identify them.
// If no tasks are scheduled, it will be reset to 0.
// A continuously increasing number to be issued to threads to
// identify them. If no tasks are scheduled, it will be reset to 0.
identifier_type highest_id_{0};
std::chrono::milliseconds tick_length_ms_;
uint8_t default_timeout_{5};

};
} // namespace detail
} // namespace crow
11 changes: 5 additions & 6 deletions tests/unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3908,26 +3908,25 @@ TEST_CASE("task_timer")
bool a = false;
bool b = false;

crow::detail::task_timer timer(io_service);
crow::detail::task_timer timer(io_service, std::chrono::milliseconds(100));
CHECK(timer.get_default_timeout() == 5);
timer.set_default_timeout(7);
CHECK(timer.get_default_timeout() == 7);

timer.schedule([&a]() {
a = true;
},
5);
}, 5);
timer.schedule([&b]() {
b = true;
});

this_thread::sleep_for(chrono::seconds(4));
this_thread::sleep_for(4 * timer.get_tick_length());
CHECK(a == false);
CHECK(b == false);
this_thread::sleep_for(chrono::seconds(2));
this_thread::sleep_for(2 * timer.get_tick_length());
CHECK(a == true);
CHECK(b == false);
this_thread::sleep_for(chrono::seconds(2));
this_thread::sleep_for(2 * timer.get_tick_length());
CHECK(a == true);
CHECK(b == true);

Expand Down

0 comments on commit b8ddff6

Please sign in to comment.