CUBRID Engine  latest
thread_daemon.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_daemon - interface for daemon threads
21  */
22 
23 #ifndef _THREAD_DAEMON_HPP_
24 #define _THREAD_DAEMON_HPP_
25 
26 #include "thread_looper.hpp"
27 #include "thread_task.hpp"
28 #include "thread_waiter.hpp"
29 
30 #include "perf_def.hpp"
31 
32 #include <string>
33 #include <thread>
34 
35 #include <cinttypes>
36 
37 // cubthread::daemon
38 //
39 // description
40 // defines a daemon thread using a looper and a task
41 // task is executed in a loop; wait times are defined by looper
42 //
43 // how to use
44 // // define your custom task
45 // class custom_task : public cubthread::task<custom_thread_context>
46 // {
47 // void execute (custom_thread_context & context) override { ... }
48 // }
49 //
50 // // define your custom context manager
51 // class custom_thread_context_manager : public cubthread::context_manager<custom_thread_context>
52 // {
53 // custom_thread_context & create_context (void) override { ... }
54 // void retire_context(custom_thread_context & context) override { ... }
55 // }
56 //
57 // // declare a looper
58 // cubthread::looper loop_pattern; // by default sleep until wakeup
59 //
60 // // context manager is required
61 // custom_thread_context_manager thr_ctxt_mgr;
62 //
63 // // and finally looping task
64 // custom_task *task = new_custom_task ();
65 //
66 // cubthread::daemon my_daemon (loop_pattern, thr_ctxt_mgr, *task); // daemon starts, executes task and sleeps
67 //
68 // std::chrono::sleep_for (std::chrono::seconds (1));
69 // my_daemon.wakeup (); // daemon executes task again
70 // std::chrono::sleep_for (std::chrono::seconds (1));
71 //
72 // // when daemon is destroyed, its execution is stopped and thread is joined
73 // // daemon will handle task deletion
74 //
75 namespace cubthread
76 {
77  class daemon
78  {
79  public:
80 
81  // daemon constructor needs:
82  // loop_pattern_arg : loop pattern for task execution
83  // context_manager_arg : context manager to create and retire thread execution context
84  // exec : task to execute
85  //
86  // NOTE: it is recommended to use dynamic allocation for execution tasks
87  //
88  template <typename Context>
89  daemon (const looper &loop_pattern_arg, context_manager<Context> *context_manager_arg,
90  task<Context> *exec, const char *name);
91  daemon (const looper &loop_pattern_arg, task_without_context *exec_arg, const char *name);
92  ~daemon();
93 
94  void wakeup (void); // wakeup daemon thread
95  void stop_execution (void); // stop_execution daemon thread from looping and join it
96  // note: this must not be called concurrently
97 
98  bool was_woken_up (void); // return true if daemon was woken up before timeout
99 
100  void reset_looper (void); // reset looper
101  // note: this applies only if looper wait pattern is of type INCREASING_PERIODS
102 
103  // statistics
104  static std::size_t get_stats_value_count (void);
105  static const char *get_stat_name (std::size_t stat_index);
106  void get_stats (cubperf::stat_value *stats_out);
107  bool is_running (void); // true, if running
108 
109  private:
110 
111  // loop functions invoked by spawned daemon thread
112 
113  // loop_with_context - after thread is spawned, it claims context from context manager and repeatedly executes
114  // task until stopped.
115  //
116  // note: context must implement interrupt_execution function
117  template <typename Context>
118  static void loop_with_context (daemon *daemon_arg, context_manager<Context> *context_manager_arg,
119  task<Context> *exec_arg, const char *name);
120 
121  // loop_without_context - just execute context-less task in a loop
122  static void loop_without_context (daemon *daemon_arg, task_without_context *exec_arg, const char *name);
123 
124  void pause (void); // pause between tasks
125  // register statistics
126  void register_stat_start (void);
127  void register_stat_pause (void);
128  void register_stat_execute (void);
129 
130  // create a set to store daemon statistic values
131  static cubperf::statset &create_statset (void);
132 
133  waiter m_waiter; // thread waiter
134  looper m_looper; // thread looper
135  std::function<void (void)> m_func_on_stop; // callback function to interrupt execution on stop request
136 
137  std::thread m_thread; // the actual daemon thread
138 
139  std::string m_name; // own name
140 
141  // stats
143  };
144 
145  /************************************************************************/
146  /* Inline/template Implementation */
147  /************************************************************************/
148 
149  template <typename Context>
150  daemon::daemon (const looper &loop_pattern_arg, context_manager<Context> *context_manager_arg,
151  task<Context> *exec, const char *name /* = "" */)
152  : m_waiter ()
153  , m_looper (loop_pattern_arg)
154  , m_func_on_stop ()
155  , m_thread ()
156  , m_name (name)
158  {
159  // starts a thread to execute daemon::loop
160  m_thread = std::thread (daemon::loop_with_context<Context>, this, context_manager_arg, exec, m_name.c_str ());
161  }
162 
163  template <typename Context>
164  void
165  daemon::loop_with_context (daemon *daemon_arg, context_manager<Context> *context_manager_arg,
166  task<Context> *exec_arg, const char *name)
167  {
168  (void) name; // suppress unused parameter warning
169  // its purpose is to help visualize daemon thread stacks
170 
171  // create execution context
172  Context &context = context_manager_arg->create_context ();
173 
174  // now that we have access to context we can set the callback function on stop
175  daemon_arg->m_func_on_stop = std::bind (&context_manager<Context>::stop_execution, std::ref (*context_manager_arg),
176  std::ref (context));
177 
178  daemon_arg->register_stat_start ();
179 
180  while (!daemon_arg->m_looper.is_stopped ())
181  {
182  // execute task
183  exec_arg->execute (context);
184  daemon_arg->register_stat_execute ();
185 
186  // take a break
187  daemon_arg->pause ();
188  daemon_arg->register_stat_pause ();
189  }
190 
191  // retire execution context
192  context_manager_arg->retire_context (context);
193 
194  // retire task
195  exec_arg->retire ();
196  }
197 
198 } // namespace cubthread
199 
200 #endif // _THREAD_DAEMON_HPP_
static std::size_t get_stats_value_count(void)
static void loop_with_context(daemon *daemon_arg, context_manager< Context > *context_manager_arg, task< Context > *exec_arg, const char *name)
generic_value< false > stat_value
Definition: perf_def.hpp:46
static cubperf::statset & create_statset(void)
void register_stat_start(void)
void get_stats(cubperf::stat_value *stats_out)
virtual void retire(void)
Definition: thread_task.hpp:75
virtual void execute(context_type &)=0
void stop_execution(void)
void register_stat_execute(void)
cubperf::statset & m_stats
void reset_looper(void)
daemon(const looper &loop_pattern_arg, context_manager< Context > *context_manager_arg, task< Context > *exec, const char *name)
static void loop_without_context(daemon *daemon_arg, task_without_context *exec_arg, const char *name)
virtual context_type & create_context(void)=0
bool is_stopped(void) const
virtual void retire_context(context_type &)=0
std::thread m_thread
static const char * get_stat_name(std::size_t stat_index)
bool was_woken_up(void)
void register_stat_pause(void)
std::function< void(void)> m_func_on_stop