Crow  1.1
A C++ microframework for the web
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 
21 namespace 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 amount of ticks. A tick is equal to 1 second.
33  class task_timer
34  {
35  public:
36  using task_type = std::function<void()>;
37  using identifier_type = size_t;
38 
39  private:
40  using clock_type = std::chrono::steady_clock;
41  using time_type = clock_type::time_point;
42 
43  public:
44  task_timer(asio::io_service& io_service):
45  io_service_(io_service), timer_(io_service_)
46  {
47  timer_.expires_after(std::chrono::seconds(1));
48  timer_.async_wait(
49  std::bind(&task_timer::tick_handler, this, std::placeholders::_1));
50  }
51 
52  ~task_timer() { timer_.cancel(); }
53 
54  void cancel(identifier_type id)
55  {
56  tasks_.erase(id);
57  CROW_LOG_DEBUG << "task_timer cancelled: " << this << ' ' << id;
58  }
59 
60  /// Schedule the given task to be executed after the default amount of ticks.
61 
62  ///
63  /// \return identifier_type Used to cancel the thread.
64  /// It is not bound to this task_timer instance and in some cases could lead to
65  /// undefined behavior if used with other task_timer objects or after the task
66  /// has been successfully executed.
67  identifier_type schedule(const task_type& task)
68  {
69  tasks_.insert(
70  {++highest_id_,
71  {clock_type::now() + std::chrono::seconds(get_default_timeout()),
72  task}});
73  CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' << highest_id_;
74  return highest_id_;
75  }
76 
77  /// Schedule the given task to be executed after the given time.
78 
79  ///
80  /// \param timeout The amount of ticks (seconds) to wait before execution.
81  ///
82  /// \return identifier_type Used to cancel the thread.
83  /// It is not bound to this task_timer instance and in some cases could lead to
84  /// undefined behavior if used with other task_timer objects or after the task
85  /// has been successfully executed.
86  identifier_type schedule(const task_type& task, std::uint8_t timeout)
87  {
88  tasks_.insert({++highest_id_,
89  {clock_type::now() + std::chrono::seconds(timeout), task}});
90  CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' << highest_id_;
91  return highest_id_;
92  }
93 
94  /// Set the default timeout for this task_timer instance. (Default: 5)
95 
96  ///
97  /// \param timeout The amount of ticks (seconds) to wait before execution.
98  void set_default_timeout(std::uint8_t timeout) { default_timeout_ = timeout; }
99 
100  /// Get the default timeout. (Default: 5)
101  std::uint8_t get_default_timeout() const { return default_timeout_; }
102 
103  private:
104  void process_tasks()
105  {
106  time_type current_time = clock_type::now();
107  std::vector<identifier_type> finished_tasks;
108 
109  for (const auto& task : tasks_)
110  {
111  if (task.second.first < current_time)
112  {
113  (task.second.second)();
114  finished_tasks.push_back(task.first);
115  CROW_LOG_DEBUG << "task_timer called: " << this << ' ' << task.first;
116  }
117  }
118 
119  for (const auto& task : finished_tasks)
120  tasks_.erase(task);
121 
122  // If no task is currently scheduled, reset the issued ids back to 0.
123  if (tasks_.empty()) highest_id_ = 0;
124  }
125 
126  void tick_handler(const error_code& ec)
127  {
128  if (ec) return;
129 
130  process_tasks();
131 
132  timer_.expires_after(std::chrono::seconds(1));
133  timer_.async_wait(
134  std::bind(&task_timer::tick_handler, this, std::placeholders::_1));
135  }
136 
137  private:
138  std::uint8_t default_timeout_{5};
139  asio::io_service& io_service_;
140  asio::basic_waitable_timer<clock_type> timer_;
141  std::map<identifier_type, std::pair<time_type, task_type>> tasks_;
142 
143  // A continuosly increasing number to be issued to threads to identify them.
144  // If no tasks are scheduled, it will be reset to 0.
145  identifier_type highest_id_{0};
146  };
147  } // namespace detail
148 } // namespace crow
A class for scheduling functions to be called after a specific amount of ticks. A tick is equal to 1 ...
Definition: task_timer.h:34
identifier_type schedule(const task_type &task, std::uint8_t timeout)
Schedule the given task to be executed after the given time.
Definition: task_timer.h:86
void set_default_timeout(std::uint8_t timeout)
Set the default timeout for this task_timer instance. (Default: 5)
Definition: task_timer.h:98
identifier_type schedule(const task_type &task)
Schedule the given task to be executed after the default amount of ticks.
Definition: task_timer.h:67
std::uint8_t get_default_timeout() const
Get the default timeout. (Default: 5)
Definition: task_timer.h:101
The main namespace of the library. In this namespace is defined the most important classes and functi...