acl  3.5.3.0
fiber.hpp
浏览该文件的文档.
1 #pragma once
2 #include <stddef.h>
3 #include "fiber_cpp_define.hpp"
4 
5 struct ACL_FIBER;
6 
7 namespace acl {
8 
9 typedef enum
10 {
11  FIBER_EVENT_T_KERNEL, // Linux: epoll, FreeBSD: kquque, Windows: iocp
16 
17 /**
18  * 协程类定义,纯虚类,需要子类继承并实现纯虚方法
19  */
21 {
22 public:
23  /**
24  * 构造函数
25  * @param running {bool} 当为 true 时,则表示当前协程已启动,仅是声明
26  * 了一个协程对象而已,以便于与 ACL_FIBER 对象绑定,此时禁止调用本对
27  * 象的 start 方法启动新协程; 当为 false 时,则需要调用 start 方法来
28  * 启动新协程
29  */
30  fiber(bool running = false);
31  virtual ~fiber(void);
32 
33  /**
34  * 在创建一个协程类对象且构造参数 running 为 false 时,需要本函数启动
35  * 协程,然后子类的重载的 run 方法将被回调,如果 running 为 true 时,
36  * 则禁止调用 start 方法
37  * @param stack_size {size_t} 创建的协程对象的栈大小
38  */
39  void start(size_t stack_size = 320000);
40 
41  /**
42  * 在本协程运行时调用此函数通知该协程退出
43  * @return {bool} 返回 false 表示本协程未启动或已经退出
44  */
45  bool kill(void);
46 
47  /**
48  * 判断当前协程是否被通知退出
49  * @return {bool} 本协程是否被通知退出
50  */
51  bool killed(void) const;
52 
53  /**
54  * 判断当前正在运行的协程是否被通知退出,该方法与 killed 的区别为,
55  * killed 首先必须有 acl::fiber 对象依托,且该协程对象有可能正在运行,
56  * 也有可能被挂起,而 self_killed 不需要 acl::fiber 对象依托且一定表示
57  * 当前正在运行的协程
58  * @return {bool}
59  */
60  static bool self_killed(void);
61 
62  /**
63  * 获得本协程对象的 ID 号
64  * @return {unsigned int}
65  */
66  unsigned int get_id(void) const;
67 
68  /**
69  * 获得当前运行的协程对象的 ID 号
70  * @return {unsigned int}
71  */
72  static unsigned int self(void);
73 
74  /**
75  * 获得当前协程在执行某个系统 API 出错时的错误号
76  * return {int}
77  */
78  int get_errno(void) const;
79 
80  /**
81  * 设置当前协程的错误号
82  * @param errnum {int}
83  */
84  void set_errno(int errnum);
85 
86  /**
87  * 获得本次操作的出错信息
88  * @return {const char*}
89  */
90  static const char* last_serror(void);
91 
92  /**
93  * 获得本次操作的出错号
94  * @return {int}
95  */
96  static int last_error(void);
97 
98  /**
99  * 将所给错误号转成描述信息
100  * @param errnum {int} 错误号
101  * @param buf {char*} 存储结果
102  * @param size {size_t} buf 空间大小
103  * @return {const char*} buf 地址
104  */
105  static const char* strerror(int errnum, char* buf, size_t size);
106 
107  /**
108  * 将错误信息输出至标准输出
109  * @param on {bool} 为 true 时,内部出错信息将输出至标准输出
110  */
111  static void stdout_open(bool on);
112 
113  /**
114  * 显式设置协程调度事件引擎类型,同时设置协程调度器为自启动模式,即当
115  * 创建协程后不必显式调用 schedule 或 schedule_with 来启动协程调度器
116  * @param type {fiber_event_t} 事件引擎类型,参见:FIBER_EVENT_T_XXX
117  * @param schedule_auto {bool} 若为 true,则创建协程对象后并运行该协程
118  * 对象后不必显式调用 schedule/schedule_with 来启动所有的协程过程,内
119  * 部会自动启动协程调度器;否则,在创建并启动协程后,必须显式地调用
120  * schedule 或 schedule_with 方式来启动协程调度器以运行所的协程过程;
121  * 内部缺省状态为 false
122  */
123  static void init(fiber_event_t type, bool schedule_auto = false);
124 
125  /**
126  * 启动协程运行的调度过程
127  */
128  static void schedule(void);
129 
130  /**
131  * 启动协程调度时指定事件引擎类型,调用本方法等于同时调用了 schedule_init
132  * 及 schedule 两个方法
133  * @param type {fiber_event_t} 事件引擎类型,参见:FIBER_EVENT_T_XXX
134  */
135  static void schedule_with(fiber_event_t type);
136 
137  /**
138  * 判断当前线程是否处于协程调度状态
139  * @return {bool}
140  */
141  static bool scheduled(void);
142 
143  /**
144  * 停止协程调度过程
145  */
146  static void schedule_stop(void);
147 
148 public:
149  /**
150  * 将当前正在运行的协程(即本协程) 挂起
151  */
152  static void yield(void);
153 
154  /**
155  * 挂起当前协程,执行等待队列中的下一个协程
156  */
157  static void switch_to_next(void);
158 
159  /**
160  * 将指定协程对象置入待运行队列中
161  * @param f {fiber&}
162  */
163  static void ready(fiber& f);
164 
165  /**
166  * 使当前运行的协程休眠指定毫秒数
167  * @param milliseconds {unsigned int} 指定要休眠的毫秒数
168  * @return {unsigned int} 本协程休眠后再次被唤醒后剩余的毫秒数
169  */
170  static unsigned int delay(unsigned int milliseconds);
171 
172  /**
173  * 获得处于存活状态的协程数量
174  * @return {unsigned}
175  */
176  static unsigned alive_number(void);
177 
178  /**
179  * 获得处于退出状态的协程对象数量
180  * @return {unsigned}
181  */
182  static unsigned dead_number(void);
183 
184  /**
185  * 线程启动后调用此函数设置当前线程是否需要 hook 系统 API,内部缺省
186  * 会 hook 系统 API
187  * @param on {bool}
188  */
189  static void hook_api(bool on);
190 
191  /**
192  * 显式调用本函数使 acl 基础库的 IO 过程协程化,在 UNIX 平台下不必显式
193  * 调用本函数,因为内部会自动 HOOK IO API
194  */
195  static void acl_io_hook(void);
196 
197  /**
198  * 调用本函数取消 acl基础库中的 IO 协程化
199  */
200  static void acl_io_unlock(void);
201 
202  /**
203  * Windows 平台下可以显式地调用此函数 Hook 一些与网络协程相关的系统 API
204  * @return {bool}
205  */
206  static bool winapi_hook(void);
207 
208  /**
209  * 获得当前系统级错误号
210  * @return {int}
211  */
212  static int get_sys_errno(void);
213 
214  /**
215  * 设置当前系统级错误号
216  * @param errnum {int}
217  */
218  static void set_sys_errno(int errnum);
219 
220 public:
221  /**
222  * 返回本协程对象对应的 C 语言的协程对象
223  * @return {ACL_FIBER* }
224  */
225  ACL_FIBER* get_fiber(void) const;
226 
227  /**
228  * 底层调用 C API 创建协程
229  * @param fn {void (*)(ACL_FIBER*, void*)} 协程函数执行入口
230  * @param ctx {void*} 传递给协程执行函数的参数
231  * @param size {size_t} 协程栈大小
232  */
233  static void fiber_create(void (*fn)(ACL_FIBER*, void*),
234  void* ctx, size_t size);
235 protected:
236  /**
237  * 虚函数,子类须实现本函数,当通过调用 start 方法启动协程后,本
238  * 虚函数将会被调用,从而通知子类协程已启动; 如果在构造函数中的参数
239  * running 为 true ,则 start 将被禁止调用,故本虚方法也不会被调用
240  */
241  virtual void run(void);
242 
243 private:
244  ACL_FIBER* f_;
245 
246  fiber(const fiber&);
247  void operator = (const fiber&);
248 
249  static void fiber_callback(ACL_FIBER* f, void* ctx);
250 };
251 
252 /**
253  * 可用作定时器的协程类
254  */
256 {
257 public:
258  fiber_timer(void);
259  virtual ~fiber_timer(void) {}
260 
261  /**
262  * 启动一个协程定时器
263  * @param milliseconds {unsigned int} 毫秒级时间
264  * @param stack_size {size_t} 协程的栈空间大小
265  */
266  void start(unsigned int milliseconds, size_t stack_size = 320000);
267 
268 protected:
269  /**
270  * 子类必须实现该纯虚方法,当定时器启动时会回调该方法
271  */
272  virtual void run(void) = 0;
273 
274 private:
275  ACL_FIBER* f_;
276 
277  fiber_timer(const fiber_timer&);
278  void operator = (const fiber_timer&);
279 
280  static void timer_callback(ACL_FIBER* f, void* ctx);
281 };
282 
283 #if defined(ACL_CPP_API)
284 
285 /**
286  * 定时器管理协程
287  */
288 template <typename T>
289 class fiber_trigger : public fiber
290 {
291 public:
292  fiber_trigger(timer_trigger<T>& timer)
293  : delay_(100)
294  , stop_(false)
295  , timer_(timer)
296  {
297  }
298 
299  virtual ~fiber_trigger(void) {}
300 
301  void add(T* o)
302  {
303  mbox_.push(o);
304  }
305 
306  void del(T* o)
307  {
308  timer_.del(o);
309  }
310 
311  timer_trigger<T>& get_trigger(void)
312  {
313  return timer_;
314  }
315 
316  // @override
317  void run(void)
318  {
319  while (!stop_) {
320  T* o = mbox_.pop(delay_);
321  if (o)
322  timer_.add(o);
323 
324  long long next = timer_.trigger();
325  long long curr = get_curr_stamp();
326  if (next == -1)
327  delay_ = 100;
328  else {
329  delay_ = next - curr;
330  if (delay_ <= 0)
331  delay_ = 1;
332  }
333  }
334  }
335 
336 private:
337  long long delay_;
338  bool stop_;
339 
340  timer_trigger<T>& timer_;
341  mbox<T> mbox_;
342 };
343 
344 #endif // ACL_CPP_API
345 
346 } // namespace acl
#define FIBER_CPP_API
ACL_CPP_API int last_error(void)
fiber_event_t
Definition: fiber.hpp:9
struct ACL_FIBER ACL_FIBER
Definition: fiber_define.h:100
ACL_CPP_API const char * last_serror(void)
ACL_CPP_API long long get_curr_stamp(void)
virtual ~fiber_timer(void)
Definition: fiber.hpp:259