重写sylar服务器框架:线程与协程模块

sylar服务器框架:线程与协程模块

线程模块

模块概述

提供线程类和线程同步类,基于pthread实现。

模块分析

Thread:线程类,通过构造函数传入线程入口函数和线程名称,线程构造之后线程开始运行。

Semaphore:计数信号量,基于sem_t实现。

Mutex: 互斥锁,基于pthread_mutex_t实现。

RWMutex: 读写锁,基于pthread_rwlock_t实现。

Spinlock: 自旋锁,基于pthread_spinlock_t实现。

CASLock: 原子锁,基于std::atomic_flag实现。

协程模块

模块概述

基于ucontext_t实现非对称协程。协程也被称为用户态轻量级线程。每个协程在创建的时候都会指定一个入口函数,保存其上下文。协程的本质就是函数和函数运行状态的组合。

协程和函数的不同之处是,函数一旦被调用,只能从头开始执行,直到函数执行结束退出,而协程则可以执行到一半就暂时让出CPU执行权(称为yield),在后面的适当的时机协程可以重新恢复运行(称为resume),在这段时间内其他的协程可以获得CPU并运行,所以协程也称为轻量级线程。

模块分析

sylar的协程模块基于ucontext_t实现,关于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上下文对应的函数中执行,相当于调用了函数
// swapcontext是sylar非对称协程实现的关键,线程主协程和子协程用这个接口进行上下文切换
int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);

非对称协程模型

在这里插入图片描述

sylar框架使用非对称协程模型,子协程只能与主协程切换,不能在子协程间切换。

协程状态

enum State {
        INIT,  /// 初始化状态
        HOLD,  /// 暂停状态
        EXEC,  /// 执行中状态
        TERM,  /// 结束状态
        READY, /// 可执行状态
        EXCEPT /// 异常状态 
    };

协程原语

对于非对称协程来说,协程除了创建语句外,只有两种操作,一种是resume,表示恢复协程运行,一种是yield,表示让出执行。协程的结束没有专门的操作,协程函数运行结束时协程即结束,协程结束时会自动调用一次yield以返回主协程。

//切换到当前协程执行 ---resume
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");
    }
}

//切换到后台执行    ---yield
void Fiber::swapOut() {
    SetThis(Scheduler::GetMainFiber());
    if(swapcontext(&m_ctx, &Scheduler::GetMainFiber()->m_ctx)) {
        SYLAR_ASSERT2(false, "swapcontext");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值