CUBRID Engine  latest
thread_looper.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * thread_looper - interface for thread looping patterns
21  */
22 
23 #ifndef _THREAD_LOOPER_HPP_
24 #define _THREAD_LOOPER_HPP_
25 
26 #include "perf_def.hpp"
27 
28 #include <array>
29 #include <atomic>
30 #include <chrono>
31 #include <functional>
32 
33 #include <cassert>
34 #include <cinttypes>
35 #include <cstdint>
36 
37 namespace cubthread
38 {
39  // definitions
41  typedef std::function<void (bool &, delta_time &)> period_function;
42 
43  // for increasing period pattern
44  const std::size_t MAX_LOOPER_PERIODS = 3;
45 
46  // forward def
47  class waiter;
48 
49  // cubthread::looper
50  //
51  // description
52  // used for loops that require pausing.
53  // defines the wait pattern between each loop iteration
54  // should be used together with a waiter
55  //
56  // how to use
57  //
58  // // define a loop pattern and then loop and put waiter to sleep on each iteration
59  //
60  // // example using increasing wait patterns
61  //
62  // // declare period type for this example
63  // typedef std::chrono::duration<std::uint64, std::chrono::milliseconds milli_period_type;
64  // // declare increasing waiting periods
65  // // wait first for 1 millisecond, then for 100, then for 1000, then infinite
66  // std::array<milli_period_type, THREE> periods = {{ 1, 100, 1000 }};
67  // // create looper
68  // looper_shared_variable = new loop_pattern (periods);
69  //
70  // // declare waiter
71  // while (!looper.is_stopped ())
72  // {
73  // // do work
74  //
75  // // now sleep until timeout or wakeup
76  // looper.put_to_sleep (waiter);
77  // // thread woke up
78  // }
79  // // loop is stopped calling looper_shared_variable->stop ();
80  //
81  class looper
82  {
83  public:
84 
85  // constructors
86 
87  // default looping pattern; always wait until wakeup on each loop
88  looper ();
89 
90  // copy other loop pattern
91  looper (const looper &other);
92 
93  // loop and wait based on value provided by setup_period_function
94  looper (const period_function &setup_period_function);
95 
96  // loop and wait for a fixed period of time
97  looper (const delta_time &fixed_period);
98 
99  // loop and wait for increasing periods of time
100  //
101  // the sleep time is increased according to periods for each sleep that times out
102  // sleep timer is reset when sleep doesn't time out
103  template<std::size_t Count>
104  looper (const std::array<delta_time, Count> periods);
105 
106  // dtor
107  ~looper (void);
108 
109  // put waiter to sleep according to loop pattern
110  void put_to_sleep (waiter &waiter_arg);
111 
112  // reset looper; only useful for increasing period pattern
113  void reset (void);
114 
115  // stop looping; no waits after this
116  bool stop (void);
117 
118  // is looper stopped
119  bool is_stopped (void) const;
120 
121  // return true if waiter was woken up before timeout, for more details see put_to_sleep (waiter &)
122  bool was_woken_up (void) const;
123 
124  // statistics
125  static std::size_t get_stats_value_count (void);
126  static const char *get_stat_name (std::size_t stat_index);
127 
128  void get_stats (cubperf::stat_value *stats_out);
129 
130  private:
131 
133  {
138  };
139 
140  void setup_fixed_waits (bool &is_timed_wait, delta_time &period);
141  void setup_infinite_wait (bool &is_timed_wait, delta_time &period);
142  void setup_increasing_waits (bool &is_timed_wait, delta_time &period);
143 
144  std::size_t m_periods_count; // the period count, used by increasing period pattern
145  delta_time m_periods[MAX_LOOPER_PERIODS]; // period array
146 
147  std::atomic<std::size_t> m_period_index; // current period index
148  std::atomic<bool> m_stop; // when true, loop is stopped; no waits
149  std::atomic<bool> m_was_woken_up; // when true, waiter was woken up before timeout
150 
151  period_function m_setup_period; // function used to refresh period on every run
152 
153  // a time point that represents the start of task execution
154  // used by put_to_sleep function in order to sleep for difference between period interval and task execution time
156 
157  // statistics
159 
160  // my type
162  };
163 
164  /************************************************************************/
165  /* Template implementation */
166  /************************************************************************/
167 
168  template<std::size_t Count>
169  looper::looper (const std::array<delta_time, Count> periods)
170  : looper ()
171  {
172  static_assert (Count <= MAX_LOOPER_PERIODS, "Count template cannot exceed MAX_LOOPER_PERIODS=3");
173  m_periods_count = std::min (Count, MAX_LOOPER_PERIODS);
174 
175  // wait increasing period on timeouts
176  for (std::size_t i = 0; i < m_periods_count; i++)
177  {
178  m_periods[i] = periods[i];
179  // check increasing periods
180  assert (i == 0 || m_periods[i - 1] < m_periods[i]);
181  }
182 
183  m_setup_period = std::bind (&looper::setup_increasing_waits, std::ref (*this), std::placeholders::_1,
184  std::placeholders::_2);
185 
187  }
188 
189 } // namespace cubthread
190 
191 #endif // _THREAD_LOOPER_HPP_
delta_time m_periods[MAX_LOOPER_PERIODS]
void put_to_sleep(waiter &waiter_arg)
void get_stats(cubperf::stat_value *stats_out)
generic_value< false > stat_value
Definition: perf_def.hpp:46
std::atomic< bool > m_was_woken_up
std::chrono::system_clock::time_point m_start_execution_time
const std::size_t MAX_LOOPER_PERIODS
void setup_infinite_wait(bool &is_timed_wait, delta_time &period)
#define assert(x)
clock::time_point time_point
Definition: perf_def.hpp:40
std::atomic< bool > m_stop
std::atomic< std::size_t > m_period_index
#define min(a, b)
bool was_woken_up(void) const
cubperf::statset & m_stats
static const char * get_stat_name(std::size_t stat_index)
std::chrono::system_clock::duration delta_time
clock::duration duration
Definition: perf_def.hpp:41
bool is_stopped(void) const
void setup_increasing_waits(bool &is_timed_wait, delta_time &period)
std::function< void(bool &, delta_time &)> period_function
void setup_fixed_waits(bool &is_timed_wait, delta_time &period)
int i
Definition: dynamic_load.c:954
period_function m_setup_period
std::size_t m_periods_count
static std::size_t get_stats_value_count(void)