CUBRID Engine  latest
thread_task.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_task.hpp
21  */
22 
23 #ifndef _THREAD_TASK_HPP_
24 #define _THREAD_TASK_HPP_
25 
26 #include <functional>
27 #include <mutex>
28 #include <thread>
29 
30 #include <cassert>
31 
32 namespace cubthread
33 {
34  // cubthread::task
35  //
36  // description:
37  // abstract class for thread tasks
38  //
39  // templates:
40  // Context - thread execution context, a helper/cache structure that can be passed to multiple tasks.
41  //
42  // how to use:
43  // 1. specialize task with Context
44  // e.g. in CUBRID we have entry_task which uses entry as context; see thread_entry_task.hpp
45  //
46  // 2. extend specialized task<custom_context> and override virtual functions
47  // override execute (Context &) to define task execution
48  // [optional] override retire function; by default it deletes task
49  //
50  // 3. execute multiple tasks using same context:
51  // custom_context context; // this is a dummy example
52  // custom_task* task_p = NULL; // using custom_task = task<custom_context>
53  //
54  // for (task_p = get_task (); task_p != NULL; task_p = get_task ())
55  // {
56  // task_p->execute (context);
57  // task_p->retire (); // this will delete task_p
58  // }
59  //
60  template <typename Context>
61  class task
62  {
63  public:
64  using context_type = Context;
65 
66  task (void) = default;
67 
68  // abstract class requires virtual destructor
69  virtual ~task (void) = default;
70 
71  // virtual functions to be implemented by inheritors
72  virtual void execute (context_type &) = 0;
73 
74  // implementation of task's retire function.
75  virtual void retire (void)
76  {
77  delete this;
78  }
79  };
80 
81  // a class based on callable execution function
82  template <typename Context>
83  class callable_task : public task<Context>
84  {
85  public:
86  using exec_func_type = std::function<void (Context &)>;
87 
88  callable_task () = delete;
89 
90  // constructor with default retire (delete/do nothing)
91  template <typename F>
92  callable_task (const F &f, bool delete_on_retire = true);
93  template <typename F>
94  callable_task (F &&f, bool delete_on_retire = true);
95 
96  // constructor with custom retire
97  template <typename FuncExec, typename FuncRetire>
98  callable_task (const FuncExec &fe, const FuncRetire &fr);
99  template <typename FuncExec, typename FuncRetire>
100  callable_task (FuncExec &&fe, FuncRetire &&fr);
101 
102  void execute (Context &ctx) final
103  {
104  m_exec_f (ctx);
105  }
106 
107  void retire () final
108  {
109  m_retire_f ();
110  }
111 
112  private:
113  std::function<void (Context &)> m_exec_f;
114  std::function<void (void)> m_retire_f;
115  };
116 
117  // context-less task specialization. no argument for execute function
118  template<>
119  class task<void>
120  {
121  public:
122  task (void) = default;
123  virtual ~task (void) = default;
124 
125  virtual void execute (void) = 0;
126  virtual void retire (void)
127  {
128  delete this;
129  }
130  };
132 
133  template<>
134  class callable_task<void> : public task_without_context
135  {
136  public:
137 
138  callable_task () = delete;
139 
140  // constructor with default retire (delete/do nothing)
141  template <typename F>
142  callable_task (const F &f, bool delete_on_retire = true);
143  template <typename F>
144  callable_task (F &&f, bool delete_on_retire = true);
145 
146  // constructor with custom retire
147  template <typename FuncExec, typename FuncRetire>
148  callable_task (const FuncExec &fe, const FuncRetire &fr);
149  template <typename FuncExec, typename FuncRetire>
150  callable_task (FuncExec &&fe, FuncRetire &&fr);
151 
152  void execute () final
153  {
154  m_exec_f ();
155  }
156 
157  void retire () final
158  {
159  m_retire_f ();
160  }
161 
162  private:
163  std::function<void (void)> m_exec_f;
164  std::function<void (void)> m_retire_f;
165  };
166 
167  // context_manager
168  //
169  // description:
170  // complex tasks may require bulky context that can take a long time to construct/destruct.
171  // context_manager abstract class is designed to pool context and hand them quickly on demand.
172  //
173  // templates:
174  // Context - thread execution context, a helper/cache structure that can be passed to multiple tasks
175  //
176  // how to use:
177  // 1. specialize context_manager with custom context
178  // e.g. see CUBRID implementation for entry_manager.
179  //
180  // 2. override create_context, retire_context and recycle_context functions
181  //
182  // 3. execute multiple tasks using same context:
183  // custom_context_manager context_mgr; // using custom_context_manager = context_manager<custom_context>
184  // custom_context& context_ref = context_mgr.create_context ();
185  // custom_task* task_p = NULL; // using custom_task = task<custom_context>
186  //
187  // for (task_p = get_task (); task_p != NULL; task_p = get_task ())
188  // {
189  // task_p->execute (context_ref);
190  // task_p->retire (); // this will delete task_p
191  // // context_mgr.recycle_context (); // optional operation before reusing context
192  // }
193  //
194  // context_mgr.retire_context (context_ref);
195  //
196  // [optional]
197  // 4. if task execution can take a very long time and you need to force stop it, you can use stop_execution:
198  // 4.1. implement context_manager::stop_execution; should notify context to stop.
199  // 4.2. you have to check stop notifications in custom_task::execute
200  // 4.3. call context_mgr.stop_execution (context_ref).
201  //
202  template <typename Context>
204  {
205  public:
206  using context_type = Context;
207 
208  // abstract class requires virtual destructor
209  virtual ~context_manager () = default;
210 
211  virtual context_type &create_context (void) = 0; // create a new thread context; cannot fail
212  virtual void retire_context (context_type &) = 0; // retire the thread context
213  virtual void recycle_context (context_type &) // recycle context before reuse
214  {
215  // usage and implementation is optional
216  }
217  virtual void stop_execution (context_type &) // notify context to stop execution
218  {
219  // usage and implementation is optional
220  }
221  };
222 
223 } // namespace cubthread
224 
226 // Implementation
228 
229 namespace cubthread
230 {
231  template<typename Context>
232  template<typename F>
233  callable_task<Context>::callable_task (const F &f, bool delete_on_retire)
234  : m_exec_f (f)
235  {
236  if (delete_on_retire)
237  {
238  m_retire_f = [this] { delete this; };
239  }
240  else
241  {
242  m_retire_f = [] {}; // do nothing
243  }
244  }
245 
246  template<typename Context>
247  template<typename F>
248  callable_task<Context>::callable_task (F &&f, bool delete_on_retire)
249  : m_exec_f (std::move (f))
250  {
251  if (delete_on_retire)
252  {
253  m_retire_f = [this] { delete this; };
254  }
255  else
256  {
257  m_retire_f = [] {}; // do nothing
258  }
259  }
260 
261  template<typename Context>
262  template<typename FuncExec, typename FuncRetire>
263  callable_task<Context>::callable_task (const FuncExec &fe, const FuncRetire &fr)
264  : m_exec_f (fe)
265  , m_retire_f (fr)
266  {
267  }
268 
269  template<typename Context>
270  template<typename FuncExec, typename FuncRetire>
271  callable_task<Context>::callable_task (FuncExec &&fe, FuncRetire &&fr)
272  : m_exec_f (std::move (fe))
273  , m_retire_f (std::move (fr))
274  {
275  }
276 
277  template<typename F>
278  callable_task<void>::callable_task (const F &f, bool delete_on_retire)
279  : m_exec_f (f)
280  {
281  if (delete_on_retire)
282  {
283  m_retire_f = [this] { delete this; };
284  }
285  else
286  {
287  m_retire_f = [] {}; // do nothing
288  }
289  }
290 
291  template<typename F>
292  callable_task<void>::callable_task (F &&f, bool delete_on_retire)
293  : m_exec_f (std::move (f))
294  {
295  if (delete_on_retire)
296  {
297  m_retire_f = [this] { delete this; };
298  }
299  else
300  {
301  m_retire_f = [] {}; // do nothing
302  }
303  }
304 
305  template<typename FuncExec, typename FuncRetire>
306  callable_task<void>::callable_task (const FuncExec &fe, const FuncRetire &fr)
307  : m_exec_f (fe)
308  , m_retire_f (fr)
309  {
310  }
311 
312  template<typename FuncExec, typename FuncRetire>
313  callable_task<void>::callable_task (FuncExec &&fe, FuncRetire &&fr)
314  : m_exec_f (std::move (fe))
315  , m_retire_f (std::move (fr))
316  {
317  }
318 } // namespace cubthread
319 
320 
321 #endif // _THREAD_TASK_HPP_
virtual ~task(void)=default
std::function< void(void)> m_exec_f
virtual void stop_execution(context_type &)
virtual void retire(void)
Definition: thread_task.hpp:75
std::function< void(void)> m_retire_f
virtual void execute(context_type &)=0
virtual void recycle_context(context_type &)
void execute(Context &ctx) final
std::function< void(void)> m_retire_f
std::function< void(Context &)> exec_func_type
Definition: thread_task.hpp:86
Context context_type
Definition: thread_task.hpp:64
std::function< void(Context &)> m_exec_f
virtual void retire(void)
task(void)=default