Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makes task_timer generic #897

Merged
merged 3 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 49 additions & 33 deletions include/crow/task_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ 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. A tick is equal to 1 second.
gittiver marked this conversation as resolved.
Show resolved Hide resolved
class task_timer
{
public:
Expand All @@ -39,14 +40,17 @@ 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(); }
Expand All @@ -57,48 +61,56 @@ namespace crow
CROW_LOG_DEBUG << "task_timer 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 (seconds) to wait before
/// execution.
gittiver marked this conversation as resolved.
Show resolved Hide resolved
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_;
}

std::chrono::milliseconds get_tick_length() const {
return tick_length_ms_;
}

private:
void process_tasks()
Expand All @@ -112,14 +124,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 +143,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 @@ -3839,26 +3839,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
Loading