珠海专业网站制作公司,计算机软件开发工资高吗,最简单的做网站,哪个网站可以做教师招聘题目fiber协程模块
以下是从sylar服务器中学的#xff0c;对其的复习#xff1b;
sylar的fiber协程模块是基于ucontext_t实现非对称协程
函数只有两个行为#xff1a;调用与返回。一旦函数返回后#xff0c;它在栈上所拥有的状态将被销毁。协程相比函数多了两个动作#xf…fiber协程模块
以下是从sylar服务器中学的对其的复习
sylar的fiber协程模块是基于ucontext_t实现非对称协程
函数只有两个行为调用与返回。一旦函数返回后它在栈上所拥有的状态将被销毁。协程相比函数多了两个动作挂起与恢复。当协程主动挂起时它的控制权将转交给另一个协程这时它所拥有的状态仍被保留着另一个协程获取控制权后在将来某个时间点也可能选择挂起从而使原协程的控制权得以恢复一旦协程像函数一样返回它所拥有的状态将被销毁。 协程是能暂停执行以在之后恢复的函数。 同样是单线程环境下协程的yield和resume一定是同步进行的一个协程的yield必然对应另一个协程的resume因为线程不可能没有执行主体。并且协程的yield和resume是完全由应用程序来控制的。与线程不同线程创建之后线程的运行和调度也是由操作系统自动完成的但协程创建后协程的运行和调度都要由应用程序来完成就和调用函数一样所以协程也被称为用户态线程。
所谓创建协程其实就是把一个函数包装成一个协程对象然后再用协程的方式把这个函数跑起来所谓协程调度其实就是创建一批的协程对象然后再创建一个调度协程通过调度协程把这些协程对象一个一个消化掉协程可以在被调度时继续向调度器添加新的调度任务所谓IO协程调度其实就是在调度协程时如果发现这个协程在等待IO就绪那就先让这个协程让出执行权等对应的IO就绪后再重新恢复这个协程的运行所谓定时器就是给调度协程预设一个协程对象等定时时间到了就恢复预设的协程对象。 ucontext_t接口 // 上下文结构体定义
typedef struct ucontext_t {// 当前上下文结束后下一个激活的上下文对象的指针只在当前上下文是由makecontext创建时有效struct ucontext_t *uc_link;// 当前上下文的信号屏蔽掩码sigset_t uc_sigmask;// 当前上下文使用的栈内存空间只在当前上下文是由makecontext创建时有效stack_t uc_stack;// 平台相关的上下文具体内容包含寄存器的值mcontext_t uc_mcontext;...
} ucontext_t;// 获取当前的上下文
int getcontext(ucontext_t *ucp);// 恢复ucp指向的上下文这个函数不会返回而是会跳转到ucp上下文对应的函数中执行相当于变相调用了函数
int setcontext(const ucontext_t *ucp);// 修改由getcontext获取到的上下文指针ucp将其与一个函数func进行绑定支持指定func运行时的参数
// 在调用makecontext之前必须手动给ucp分配一段内存空间存储在ucp-uc_stack中这段内存空间将作为func函数运行时的栈空间
// 同时也可以指定ucp-uc_link表示函数运行结束后恢复uc_link指向的上下文
// 如果不赋值uc_link那func函数结束时必须调用setcontext或swapcontext以重新指定一个有效的上下文否则程序就跑飞了
// makecontext执行完后ucp就与函数func绑定了调用setcontext或swapcontext激活ucp时func就会被运行
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);// 恢复ucp指向的上下文同时将当前的上下文存储到oucp中
// 和setcontext一样swapcontext也不会返回而是会跳转到ucp上下文对应的函数中执行相当于调用了函数
int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);sylar协程模块设计
sylar使用非对称协程模型也就是子协程只能和线程主协程切换而不能和另一个子协程切换并且在程序结束时一定要再切回主协程以保证程序能正常结束
sylar对每个协程设计了6种状态
/*** brief 协程状态*/
enum State {/// 初始化状态INIT,/// 暂停状态HOLD,/// 执行中状态EXEC,/// 结束状态TERM,/// 可执行状态READY,/// 异常状态EXCEPT
};fiber类包含以下成员变量
/// 协程id
uint64_t m_id 0;
/// 协程栈大小
uint32_t m_stacksize 0;
/// 协程状态
State m_state READY;
/// 协程上下文
ucontext_t m_ctx;
/// 协程栈地址
void *m_stack nullptr;
/// 协程入口函数
std::functionvoid() m_cb;定义了两个全局静态变量用于生成协程id和统计当前的协程数
/// 全局静态变量用于生成协程id
static std::atomicuint64_t s_fiber_id{0};
/// 全局静态变量用于统计当前的协程数
static std::atomicuint64_t s_fiber_count{0};以下两个线程局部变量用于保存协程上下文信息
/// 线程局部变量当前线程正在运行的协程
static thread_local Fiber *t_fiber nullptr;
/// 线程局部变量当前线程的主协程切换到这个协程就相当于切换到了主线程中运行智能指针形式
static thread_local Fiber::ptr t_thread_fiber nullptr;构造函数 带参数的构造函数用于构造子协程初始化子协程的ucontext_t上下文和栈空间要求必须传入协程的入口函数以及可选的协程栈大小。不带参的构造函数用于初始化当前线程的协程功能构造线程主协程对象
/*** brief 构造函数* attention 无参构造函数只用于创建线程的第一个协程也就是线程主函数对应的协程* 这个协程只能由GetThis()方法调用所以定义成私有方法*/
Fiber::Fiber(){SetThis(this);m_state RUNNING;if (getcontext(m_ctx)) {SYLAR_ASSERT2(false, getcontext);}s_fiber_count;m_id s_fiber_id; // 协程id从0开始用完加1SYLAR_LOG_DEBUG(g_logger) Fiber::Fiber() main id m_id;
}/*** brief 构造函数用于创建用户协程* param[] cb 协程入口函数* param[] stacksize 栈大小默认为128k*/
Fiber::Fiber(std::functionvoid() cb, size_t stacksize): m_id(s_fiber_id), m_cb(cb) {s_fiber_count;m_stacksize stacksize ? stacksize : g_fiber_stack_size-getValue();m_stack StackAllocator::Alloc(m_stacksize);if (getcontext(m_ctx)) {SYLAR_ASSERT2(false, getcontext);}m_ctx.uc_link nullptr;m_ctx.uc_stack.ss_sp m_stack;m_ctx.uc_stack.ss_size m_stacksize;makecontext(m_ctx, Fiber::MainFunc, 0);SYLAR_LOG_DEBUG(g_logger) Fiber::Fiber() id m_id;
}/*** brief 返回当前线程正在执行的协程* details 如果当前线程还未创建协程则创建线程的第一个协程* 且该协程为当前线程的主协程其他协程都通过这个协程来调度也就是说其他协程* 结束时,都要切回到主协程由主协程重新选择新的协程进行resume* attention 线程如果要创建协程那么应该首先执行一下Fiber::GetThis()操作以初始化主函数协程*/
Fiber::ptr GetThis(){if (t_fiber) {return t_fiber-shared_from_this();}Fiber::ptr main_fiber(new Fiber);SYLAR_ASSERT(t_fiber main_fiber.get());t_thread_fiber main_fiber;return t_fiber-shared_from_this();
}协程原语的实现,挂起和恢复
/*** brief 将当前协程切换到运行状态(与调度协程)* pre getState() ! EXEC* post getState() EXEC*/
void Fiber::swapIn() {SetThis(this);SYLAR_ASSERT(m_state ! EXEC);m_state EXEC;if(swapcontext(Scheduler::GetMainFiber()-m_ctx, m_ctx)) {SYLAR_ASSERT2(false, swapcontext);}
}/*** brief 将当前协程切换到后台(与调度协程)*/
void Fiber::swapOut() {SetThis(Scheduler::GetMainFiber());if(swapcontext(m_ctx, Scheduler::GetMainFiber()-m_ctx)) {SYLAR_ASSERT2(false, swapcontext);}
}/*** brief 将当前线程切换到执行状态(与主协程)* pre 执行的为当前线程的主协程*/
void Fiber::call() {SetThis(this);m_state EXEC;SYLAR_LOG_ERROR(g_logger) getId();if(swapcontext(t_threadFiber-m_ctx, m_ctx)) {SYLAR_ASSERT2(false, swapcontext);}
}/*** brief 将当前线程切换到后台(与主协程)* pre 执行的为该协程* post 返回到线程的主协程*/
void Fiber::back() {SetThis(t_threadFiber.get());if(swapcontext(m_ctx, t_threadFiber-m_ctx)) {SYLAR_ASSERT2(false, swapcontext);}
}协程入口函数
void Fiber::MainFunc() {Fiber::ptr cur GetThis(); // GetThis()的shared_from_this()方法让引用计数加1SYLAR_ASSERT(cur);cur-m_cb(); // 这里真正执行协程的入口函数cur-m_cb nullptr;cur-m_state TERM;auto raw_ptr cur.get(); // 手动让t_fiber的引用计数减1cur.reset();raw_ptr-yield(); // 协程结束时自动yield以回到主协程
}协程的重置 重复利用已结束的协程复用其栈空间创建新协程
void Fiber::reset(std::functionvoid() cb) {SYLAR_ASSERT(m_stack);SYLAR_ASSERT(m_state TERM);m_cb cb;if (getcontext(m_ctx)) {SYLAR_ASSERT2(false, getcontext);}m_ctx.uc_link nullptr;m_ctx.uc_stack.ss_sp m_stack;m_ctx.uc_stack.ss_size m_stacksize;makecontext(m_ctx, Fiber::MainFunc, 0);m_state READY;
}