Crow  1.1
A C++ microframework for the web
 
Loading...
Searching...
No Matches
task_timer.h
1#pragma once
2
3#ifdef CROW_USE_BOOST
4#include <boost/asio.hpp>
5#include <boost/asio/basic_waitable_timer.hpp>
6#else
7#ifndef ASIO_STANDALONE
8#define ASIO_STANDALONE
9#endif
10#include <asio.hpp>
11#include <asio/basic_waitable_timer.hpp>
12#endif
13
14#include <chrono>
15#include <functional>
16#include <map>
17#include <vector>
18
19#include "crow/logging.h"
20
21namespace crow
22{
23#ifdef CROW_USE_BOOST
24 namespace asio = boost::asio;
25 using error_code = boost::system::error_code;
26#else
27 using error_code = asio::error_code;
28#endif
29 namespace detail
30 {
31
32 /// A class for scheduling functions to be called after a specific
33 /// amount of ticks. Ther tick length can be handed over in constructor,
34 /// the default tick length is equal to 1 second.
36 {
37 public:
38 using task_type = std::function<void()>;
39 using identifier_type = size_t;
40
41 private:
42 using clock_type = std::chrono::steady_clock;
43 using time_type = clock_type::time_point;
44 public:
45 task_timer(asio::io_context& io_context,
46 const std::chrono::milliseconds tick_length =
47 std::chrono::seconds(1)) :
48 io_context_(io_context), timer_(io_context_),
49 tick_length_ms_(tick_length)
50 {
51 timer_.expires_after(tick_length_ms_);
52 timer_.async_wait(
53 std::bind(&task_timer::tick_handler, this,
54 std::placeholders::_1));
55 }
56
57 ~task_timer() { timer_.cancel(); }
58
59 /// Cancel the scheduling of the given task
60 ///
61 /// \param identifier_type task identifier of the task to cancel.
62 void cancel(identifier_type id)
63 {
64 tasks_.erase(id);
65 CROW_LOG_DEBUG << "task_timer task cancelled: " << this << ' ' << id;
66 }
67
68 /// Schedule the given task to be executed after the default amount
69 /// of ticks.
70
71 ///
72 /// \return identifier_type Used to cancel the thread.
73 /// It is not bound to this task_timer instance and in some cases
74 /// could lead to undefined behavior if used with other task_timer
75 /// objects or after the task has been successfully executed.
76 identifier_type schedule(const task_type& task)
77 {
78 return schedule(task, get_default_timeout());
79 }
80
81 /// Schedule the given task to be executed after the given time.
82
83 ///
84 /// \param timeout The amount of ticks to wait before execution.
85 ///
86 /// \return identifier_type Used to cancel the thread.
87 /// It is not bound to this task_timer instance and in some cases
88 /// could lead to undefined behavior if used with other task_timer
89 /// objects or after the task has been successfully executed.
90 identifier_type schedule(const task_type& task, uint8_t timeout)
91 {
92 tasks_.insert({++highest_id_,
93 {clock_type::now() + (timeout * tick_length_ms_),
94 task}});
95 CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' <<
96 highest_id_;
97 return highest_id_;
98 }
99
100 /// Set the default timeout for this task_timer instance.
101 /// (Default: 5)
102
103 ///
104 /// \param timeout The amount of ticks to wait before
105 /// execution.
106 /// For tick length \see tick_length_ms_
107 void set_default_timeout(uint8_t timeout) {
108 default_timeout_ = timeout;
109 }
110
111 /// Get the default timeout. (Default: 5)
112 uint8_t get_default_timeout() const {
113 return default_timeout_;
114 }
115
116 /// returns the length of one tick.
117 std::chrono::milliseconds get_tick_length() const {
118 return tick_length_ms_;
119 }
120
121 private:
122 void process_tasks()
123 {
124 time_type current_time = clock_type::now();
125 std::vector<identifier_type> finished_tasks;
126
127 for (const auto& task : tasks_)
128 {
129 if (task.second.first < current_time)
130 {
131 (task.second.second)();
132 finished_tasks.push_back(task.first);
133 CROW_LOG_DEBUG << "task_timer called: " << this <<
134 ' ' << task.first;
135 }
136 }
137
138 for (const auto& task : finished_tasks)
139 tasks_.erase(task);
140
141 // If no task is currently scheduled, reset the issued ids back
142 // to 0.
143 if (tasks_.empty()) highest_id_ = 0;
144 }
145
146 void tick_handler(const error_code& ec)
147 {
148 if (ec) return;
149
150 process_tasks();
151
152 timer_.expires_after(tick_length_ms_);
153 timer_.async_wait(
154 std::bind(&task_timer::tick_handler, this, std::placeholders::_1));
155 }
156
157 private:
158 asio::io_context& io_context_;
159 asio::basic_waitable_timer<clock_type> timer_;
160 std::map<identifier_type, std::pair<time_type, task_type>> tasks_;
161
162 // A continuously increasing number to be issued to threads to
163 // identify them. If no tasks are scheduled, it will be reset to 0.
164 identifier_type highest_id_{0};
165 std::chrono::milliseconds tick_length_ms_;
166 uint8_t default_timeout_{5};
167
168 };
169 } // namespace detail
170} // namespace crow
Definition task_timer.h:36
void cancel(identifier_type id)
Definition task_timer.h:62
uint8_t get_default_timeout() const
Get the default timeout. (Default: 5)
Definition task_timer.h:112
identifier_type schedule(const task_type &task, uint8_t timeout)
Schedule the given task to be executed after the given time.
Definition task_timer.h:90
std::chrono::milliseconds get_tick_length() const
returns the length of one tick.
Definition task_timer.h:117
void set_default_timeout(uint8_t timeout)
Definition task_timer.h:107
identifier_type schedule(const task_type &task)
Definition task_timer.h:76
The main namespace of the library. In this namespace is defined the most important classes and functi...