【sylar-webserver】5 协程调理模块

打印 上一主题 下一主题

主题 1953|帖子 1953|积分 5859

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
协程调理模块,必要把前面的线程模块和协程模块结合使用 ~
计划思路



  • 构造函数界说 线程池 根本信息。
  • start(),创建线程池,每个线程创建都实行 run()。
  • 每个线程在 run() 里,查找任务队列 m_tasks。如果获取到任务后,创建协程并切换实行 ~ 如果没任务切换到 idel 协程等待 ~
  • 添加任务到 m_tasks。
  • stop(),调用tickle(),唤醒全部线程,等待全部的任务完成。
重要的函数:

  • 构造函数
  • Scheduler(size_t threads, bool use_caller, const std::string &name) // 模板函数,添加任务
  • start()
  • run()
  • stop()
重要的变量:


  • 线程变量:

    • static thread_local Scheduler* t_scheduler;当火线程的调理器,同一个调理器下的全部线程贡献同一个实例。
    • static thread_local Fiber* t_scheduler_fiber; 当火线程的调理协程,每个线程都独一份。

  • Scheduler类变量

    • std::vector<Thread::ptr> m_threads; 线程池
    • std::list<ScheduleTask> m_tasks; 任务队列
    • bool m_useCaller; 主线程是否添加调理

      • 当 m_useCaller = true; 主线程添加调理
      • Fiber::ptr m_rootFiber; 调理器地点线程的调理协程
      • int m_rootThread; 调理地点的线程id


具体调理必要细分情况:


  • 主线程不添加到调理器
    这种较为简朴。

    • Scheduler(),界说线程池变量
    • start(),创建子线程 实行 run()
    • run(),如果是子线程,必要创建主协程赋值给 t_scheduler_fiber 作为调理协程。idle_fiber协程。cb_fiber任务协程。从任务队列拿去任务,然后设置cb_fiber,切换实行。(主协程 <----> cb_fiber)。如果没有任务,切换idel协程,阻塞(iomanager里会使用epoll_wait重写这个方法,这里还只是象征性的 等待。重写必要注意,idle_fiber是在while循环里,也就是只要不stop,idle_fiber会一直存在。)(主协程 <----> idle_fiber)。
    • stop(),设置m_stopping,唤起子线程,等待任务实行结束。【纯线程池 模子下,只要是外部线程即可stop】

  • 主线程添加到调理器
    其实这里,最重要的是 三协程的切换设置。
    (主协程 — 调理协程 — 任务协程)

    • Scheduler(),界说线程池变量。创建调理协程赋值 m_rootFiber 作为当前主线程的调理协程,运行run()。赋值t_scheduler_fiber = m_rootFiber.get() ,这就是当前主线程的调理协程。赋值 m_rootThread 当前主线程(用于判断是否是主线程)。
    • start(),同上,创建子线程,实行run()
    • run(),此时额外增长 主线程的 调理过程。如果是主线程,那么 t_scheduler_fiber 已经赋值为调理协程。直接拿去任务实行,大概切换idle等待。
    • stop(),特殊性在于,主线程一直是主协程在 初始化/添加任务。只有在stop里,切换到 m_rootFiber 调理协程消耗任务。【use_caller 模式下实行stop(),必须是主线程,因为我们必要 切换到 主线程里的调理协程 消耗一下任务】

三种协程的切换

对于 主协程,调理协程,任务协程。
重构了 协程模块 里的 yield 和 resume
yield:任务协程 --> 调理协程 —> 主协程
resume: 主协程 —> 调理协程 —> 任务协程
Fiber增长一个类变量
bool m_runInScheduler; // 本协程是否参与调理器调理,相当于当前协程是否是任务协程。
  1. void Fiber::yield(){
  2.         SYLAR_ASSERT(m_state == TERM || m_state == RUNNING)     // 当前子协程可以是 TERM,RUNNING
  3.         if(m_state != TERM){    // 如果没有结束,中途进行yield,状态设置为READY,可能还会回来继续执行。
  4.         m_state = READY;
  5.     }
  6.         if(m_runInScheduler){
  7.                 if(swapcontext(&m_ctx, &(Scheduler::GetMainFiber()->m_ctx))){
  8.                         ...
  9.                 }
  10.         }else{
  11.                 if(swapcontext(&m_ctx, &(t_thread_fiber->m_ctx))){
  12.                         ...
  13.                 }
  14.         }
  15. }
  16. void Fiber::resume(){
  17.         SYLAR_ASSERT(m_state == READY);
  18.         // 切换前,提前设置状态和 当前线程运行的协程。
  19.         SetThis(this);
  20.         m_state = RUNNING;
  21.         if(m_runInScheduler){ // 相当于当前协程,是任务协程。 t_scheduler_fiber --> t_fiber
  22.                 if(swapcontext(&(Scheduler::GetMainFiber()->m_ctx), &m_ctx)){
  23.                         ...
  24.                 }
  25.         }else { // t_thread_fiber --> t_scheduler_fiber
  26.                 if(swapcontext(&(t_thread_fiber->m_ctx), &m_ctx)){
  27.                         ...
  28.                 }
  29.         }
  30. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

科技颠覆者

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表