我是靠谱客的博主 健壮蜡烛,这篇文章主要介绍解析sylar协程库的实现(持续更新中)Fiber,现在分享给大家,希望可以做个参考。

声明该协程/协程调度/IO协程调度 框架源码均是出自sylar库如有转发注意声明

Fiber

复制代码
1
2
注意事项在看本文章之前读者应该需要了解的知识点: c++11、linux/uinx操作系统下的ucontext函数族、协程的基本原理、以及什么是对称协程和非对称协程

fiber(协程)类的定义

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// 协程数量 static std::atomic<uint64_t> t_fiberCount{0}; // 协程ID static std::atomic<uint64_t> t_fiberId{0}; // 当前线程正在运行的协程 static thread_local Fiber *t_fiber = nullptr; // 当前线程的主协程 static thread_local Fiber::ptr t_threadFiber = nullptr; // config定义协程默认协程大小(读者可以使用自己实现的config或者define)sylar库使用yaml实现的配置文件(默认申请1mb) static auto g_stack_size = Config::Lookup<uint64_t>("fiber.stack_size", 1024 * 1024, "fiber stack size"); // log日志打印输出(这里为了方便就暂时使用标准输出即可读者也可使用自自己实现的log) static Logger::ptr g_logger = SYLAR_ROOT_LOGGER("") // 以下是协程类具体的封装和实现 class Fiber : public std::enable_shared_from_this<Fiber>{ public: typedef std::shared_ptr<Fiber> ptr; // 定义协程状态 enum State{ INIT, // 初始化状态 EXEC, // 运行状态 HOLD, // yield状态hold READY, // yield状态ready TERM, // 结束状态 EXCEPT // 异常状态(个人感觉没啥用) }; // 用于创建子协程 Fiber(std::function<void()> cb, size_t stack_size = 0); // 协程占用CPU开始执行(EXEC) void swapIn(); // 协程让出CPU进入yield状态 void swapOut(); // 获取协程状态 State getState() const { return m_state; } // 重置协程 void reset(std::function<void()> cb); // 回收系统资源 ~Fiber(); public: // 获取当前线程正在运行的协程 static Fiber::ptr GetThis(); // 设置当前线程正在运行的协程 static void SetThis(Fiber *fiber); // 让当前正在运行协程yield并设置状态为hold static void YieldToHold(); // 让当前正在运行协程yield并设置状态为ready static void YieldToReady(); // 获取协程数量 static uint64_t GetFiberTotalCount(); // 获取当前正在执行的协程ID static uint64_t GetFiberID(); private: /* 用于创建主协程的注意这点很重要因为实现的是非对称的协程所以主协程在当前线程中 主协程只能有一个并且一定要有一个协程做为子协程 */ Fiber(); // 协程入口函数 static void MainFunc(); private: // 定义一些协程的私有数据 // 使用posix c提供的上下文实现协程 ucontext_t m_ctx; // 栈空间大小 size_t m_stack_size = 0; // 栈空间(什么类型都可以个人习惯使用u_char *) u_char *m_stack = nullptr; // 协程运行状态 State m_state = INIT; // 协程ID uint64_t m_fiber_id = 0; // 需要执行任务的回调函数 std::function<void()> m_cb; };

fiber(协程)类的具体实现

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* fiber实现之前sylar库封装了那些东西 SYALR_ASSERT2(x, s)、SYLAR_ASSERT(x)这两个宏定义读者可以简单的了解为assert即可 其底层实现实现不过是打印对应协程出错时的栈信息(backtrace函数族+assert) */ // 具体实现之前先统一一下内存申请方式(具体的可以视情况而定)sylar库中使用malloc当然malloc已经非常优秀了自己封装的内存池肯定没有人家写的好至于内存泄漏啥的你认为自己写的内存分配器就不会?最主要的就连linux系统都在用malloc。。。当然也可以使用优秀的开源项目比如tcmalloc或者jemalloc(本人只读过tcmalloc部分代码,重点理解tcmalloc的实现原理)这里之所以封装是因为在linux/unix操作系统还能使用mmap进行内存申请 class MallocStackAlloc{ public: static void *Alloc(size_t size) { return malloc(size); } static void Dealloc(void *ptr, size_t size) { return free(ptr); } }; using StackAlloc = MallocStackAlloc; // 用于创建子协程 Fiber::Fiber(std::function<void()> cb, size_t stack_size) : m_cb(cb), m_fiber_id(++t_fiberId) { // 栈空间大小 m_stack_size = stack_size ? stack_size : g_stack_size; // 获取当前上下文信息 if (getcontext(&m_ctx)) { SYLAR_ASSERT2(false, "getcontex"); } m_stack = static<u_char *>(StackAlloc::Alloc(m_stack_size)); m_ctx.uc_link = nullptr; m_ctx.uc_stack.ss_size = m_stack_size; m_ctx.uc_stack.ss_sp = m_stack; // 上下文绑定入口函数 makecontext(&m_ctx, &Fiber::MainFunc, 0); ++t_fiberCount; } /* 用于创建主协程的注意这点很重要因为实现的是非对称的协程所以主协程在当前线程中 主协程只能有一个并且一定要有一个协程做为子协程 */ Fiber::Fiber() : m_fiber_id(++t_fiberId) { m_state = EXCE; // 设置当前正在运行的协程 SetThis(this); // 获取当前上下文信息 if (getcontext(&m_ctx)) { SYLAR_ASSERT2(false, "getcontex"); } ++t_fiberCount; } // 协程占用CPU开始执行(EXEC) void Fiber::swapIn() { SYLAR_ASSERT(m_state != EXEC); SetThis(this); m_state = EXEC; if (swapcontext(&t_threadFiber->m_ctx, &m_ctx)) { SYALR_ASSERT2(false, "swapcontext"); } } // 协程让出CPU进入yield状态 void Fiber::swapOut() { SetThis(t_threadFiber.get()); if (swapcontext(&m_ctx, &t_threadFiber->m_ctx)) { SYALR_ASSERT2(false, "swapcontext"); } } // 重置协程 void Fiber::reset(std::function<void()> cb) { SYLAR_ASSERT(m_state == INIT || m_state == TERM || m_state == EXCEPT); m_state = INIT; m_cb.swap(cb); if (getcontext(&m_ctx)) { SYLAR_ASSERT2(false, "getcontext"); } m_ctx.uc_link = nullptr; m_ctx.uc_stack.ss_size = m_stack_size; m_ctx.uc_stack.ss_sp = m_stack; makecontext(&m_ctx, &Fiber::MainFunc, 0); } // 获取当前线程正在运行的协程 Fiber::ptr Fiber::GetThis() { if (!t_fiber) { t_threadFiber.reset(new Fiber); SYLAR_ASSERT(t_threadFiber.get() == t_fiber); } return t_fiber->shared_from_this(); } // 设置当前线程正在运行的协程 void Fiber::SetThis(Fiber *fiber) { t_fiber = fiber; } // 让当前正在运行协程yield并设置状态为hold void Fiber::YieldToHold() { Fiber::ptr fiber = GetFiber(); fiber->m_state = HOLD; fiber->swapOut(); } // 让当前正在运行协程yield并设置状态为ready void Fiber::YieldToReady() { Fiber::ptr fiber = GetFiber(); fiber->m_state = READY; fiber->swapOut(); } // 获取协程数量 uint64_t Fiber::GetFiberTotalCount() { return t_fiberCount; } // 获取当前正在执行的协程ID uint64_t Fiber::GetFiberID() { Fiber::ptr fiber = GetThis(); return fiber->m_fiber_id; } // 协程入口函数 void Fiber::MainFunc() { Fiber::ptr fiber = GetThis(); try { fiber->cb(); fiber->cb = nullptr; fiber->m_state = TERM; } catch(std::exception &e) { SYLAR_LOG_ERROR(g_logger) << "Fiber Exception: " << e.what(); fiber->m_state = EXCEPT; } catch(...) { SYLAR_LOG_ERROR(g_logger) << "Fiber Exception!"; fiber->m_state = EXCEPT; } Fiber *ptr = fiber.get(); fiber.reset(); ptr.swapOut(); } // 释放资源 Fiber::~Fiber() { if (m_stack) { // 有栈空间表示为子协程 SYLAR_ASSERT(m_state == INIT || m_state == TERM || m_state == EXCEPT); StackAlloc::Dealloc(m_stack, m_size); } else { SYALR_ASSERT(!m_cb); SYALR_ASSERT(m_state == EXEC); t_threadFiber = nullptr; // 主协程一定要指向空 // 当前运行的协程是不是主协程 Fiber::ptr fiber = GetFiber(); if (*fiber == this) { SetThis(nullptr); } } --t_fiberCount; }

最后

以上就是健壮蜡烛最近收集整理的关于解析sylar协程库的实现(持续更新中)Fiber的全部内容,更多相关解析sylar协程库内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(78)

评论列表共有 0 条评论

立即
投稿
返回
顶部