TaskControl:全局一个,控制所有TaskGroup和工作线程,初始化时根据配置数量创建指定数量的工作线程。包含4个parkinglot供线程睡眠等待任务使用。非工作线程添加任务时通过TaskControl进行,在TaskControl中随机选择一个TaskGroup并将任务添加到该TaskGroup队列中

TaskGroup:每个工作线程绑定一个TaskGroup,TaskGroup中包含工作队列等信息

源码地址:bthread/task_control.h bthread/task_control.cpp bthread/task_group.h bthread/task_group_inl.h bthread/task_group.cpp

// 工作线程执行函数

TaskGroup::run_main_task() {

    TaskGroup dummy

    // 每次获取一个待执行的bthread,若没有在parkinglot上睡眠等待唤醒

    while (wait_task(&tid)) {

        // 切换到tid标记的bthread的上下文

        sched_to(&dummy, tid)

        // 这里工作线程得到调度,回到工作线程的上下文继续执行

        // 下一个任务分配栈失败或者指定了pthread模式,直接在pthread的栈上调用task_runner()

        if (cur_meta.tid != main_tid)

            task_runner()

    }

    // 这里线程退出

}

// 此函数中发生上下文切换

sched_to(TaskGroup g, TaskMeta next_meta) {

    cur_meta = g.cur_meta

    if (next_meta != cur_meta) {

        // 切换cur_meta和线程本地存储

        g.cur_meta = next_meta

        cur_meta.local_storage = tls_bls

        tls_bls = next_meta.local_storage

        if (cur_meta->stack != nullptr) {

            if (next_meta.stack != cur_meta.stack) {

                // 若next_meta有自己的栈,jump_stack切换到next_meta的栈

                jump_stack(cur_meta->stack, next_meta.stack)

                // cur_meta再次得到调度,从这里开始执行,由于bthread允许偷任务,可能此时是其他工作线程在执行,需要切换

                g = tls_task_group

            else {

                // 一个pthread_task切换到另一个pthread_task,只能在工作线程的栈上发生

                CHECK(cur_meta.stack == g.main_stack)

            }

        }

    }

    while (g.last_context_remained) {

        fn = g.last_context_remained

        g.last_context_remained = nullptr

        fn()

        g = tls_task_group

    }

    // 到这里此函数返回,继续执行cur_meta所在的bthread任务,即该bthread中调用sched_to的下一行代码

}

// bthread栈的初始函数,第一次jump到一个bthread栈的时候调用此函数

void task_runner() {

    g = tls_task_group

    while (g.last_context_remained) {

        fn = g.last_context_remained

        fn()

        g = tls_task_group

    }

    do {

        m = g.cur_meta

        m.user_func(arg)    // 执行用户函数

        g = tls_task_group  // 可能发生过上下文切换,这里切换回来了,需要更新TaskGroup

        g.set_remained(release_last_context, &m)    // 用户函数已经执行完了,设置销毁栈

        ending_sched(&g)

    while(g.cur_meta.tid != g.main_tid)

}

// 特殊处理的sched,已知当前bthread已经执行完成,栈等相关资源不再需要时调用

ending_sched(TaskGroup g) {

    next_tid = g.next_sched_tid()

    cur_meta = g.cur_meta

    next_meta = address_meta(next_tid)

    if (next_meta.stack == nullptr) {

        // 若next_meta没有栈且需要的栈类型和cur_meta一致,那么直接让next_meta使用cur_meta的栈,节省释放和重新分配的开销

        if (next_meta.stack_type() == cur_meta.stack_type())

            next_meta.set_stack(cur_meta.release_stack())

        else {

            // 新初始化一个栈,起始函数为task_runner,第一次jump到这个栈的时候调用

            stack = get_stack(next_meta.stack_type(), task_runner)

            if (stack)

                next_meta.set_stack(stack)

            else {

                // 可能没有足够的内存支持mmap或者栈类型本身就是pthread的,直接用工作线程的栈执行

                next_meta.stack_type = BTHREAD_STACKTYPE_PTHREAD

                next_meta.set_stack(g.main_stack)

            }

        }

    }

    sched_to(g, next_meta)

}

bthread源码分析(七)bthread调度逻辑相关推荐

  1. TeamTalk客户端源码分析七

    TeamTalk客户端源码分析七 一,CBaseSocket类 二,select模型 三,样例分析:登录功能 上篇文章我们分析了network模块中的引用计数,智能锁,异步回调机制以及数据的序列化和反 ...

  2. v03.06 鸿蒙内核源码分析(时钟任务) | 调度的源动力从哪来 | 百篇博客分析HarmonyOS源码

    子曰:"巧言.令色.足恭,左丘明耻之,丘亦耻之.匿怨而友其人,左丘明耻之,丘亦耻之."<论语>:公冶长篇 百篇博客系列篇.本篇为: v03.xx 鸿蒙内核源码分析(时钟 ...

  3. v06.03 鸿蒙内核源码分析(调度队列) | 内核调度也需要排队 | 百篇博客分析HarmonyOS源码

    子曰:"君子食无求饱,居无求安,敏于事而慎于言,就有道而正焉,可谓好学也已."<论语>:学而篇 百篇博客系列篇.本篇为: v06.xx 鸿蒙内核源码分析(调度队列篇) ...

  4. Spring Core Container 源码分析七:注册 Bean Definitions

    前言 原本以为,Spring 通过解析 bean 的配置,生成并注册 bean defintions 的过程不太复杂,比较简单,不用单独开辟一篇博文来讲述:但是当在分析前面两个章节有关 @Autowi ...

  5. 【转】ABP源码分析七:Setting 以及 Mail

    本文主要说明Setting的实现以及Mail这个功能模块如何使用Setting. 首先区分一下ABP中的Setting和Configuration. Setting一般用于需要通过外部配置文件(或数据 ...

  6. spring boot 源码分析(七) 事件机制 之 SpringApplicationEvent

    2019独角兽企业重金招聘Python工程师标准>>> 一.前言 前面的文章我们讲解了一下spring boot配置文件加载的相关源码分析,下面我们将从源码角度讲解一下spring  ...

  7. Spring Security源码分析七:Spring Security 记住我

    有这样一个场景--有个用户初访并登录了你的网站,然而第二天他又来了,却必须再次登录.于是就有了"记住我"这样的功能来方便用户使用,然而有一件不言自明的事情,那就是这种认证状态的&q ...

  8. 我的世界java刷怪数量_我的世界Minecraft源码分析(1):刷怪逻辑

    这个系列通过对我的世界Minecraft源码进行拆分讲解,让大家可以清除的了解一款游戏是怎么一步步被实现出来的,下面就介绍Minecraft源码第一篇内容,关于刷怪逻辑. 生成循环 生物大致划分为四种 ...

  9. springfox源码_springfox 源码分析(七) 文档初始化

    时间:2019-5-23 20:12:04 地点:家中 通过前面几篇文章对springfox的介绍,以及我们的学习准备工作,这篇我们将正式来探索springfox是如何初始化的 我们在学算法的时候,其 ...

最新文章

  1. mysql基本语句集合
  2. 编译32位扩展在64位环境
  3. 关系型数据库的ACID规则
  4. 3 种发布策略,解决 K8s 中快速交付应用的难题
  5. react 父子组件传值
  6. fedora 16 面部显示
  7. ab压力 failed_ab测试时结果显示大量Request failed的情况分析
  8. onvif协议服务器端口,大华录像机添加海康摄像头,设置了onvif协议也不行,如何解决?...
  9. 产品-Axure9英文版,使用DynamicPanel动态面板制作循环、自动滚动列表
  10. vot toolkit的超详细使用(多图)
  11. Python办公系列--Python创建Excel工作簿
  12. A19.从零开始前后端react+flask - 删除前后端数据
  13. No resource found that matches the given name 'Theme.AppCompat.Light.DarkActionBar'
  14. Hadoop的数据压缩
  15. 小程序 微信统计表格_微信小程序制作表格的方法
  16. asp.net_ImageMap热区
  17. 简述驱动桥的动力传递路线_驱动桥
  18. 《英雄联盟》——召唤师峡谷模式 游戏设计元素分析
  19. 我为什么会喜欢《莺莺传》
  20. ERA5再分析资料,绘制2020年7月13日0点(UTC)总降水全国分布图

热门文章

  1. SE01(理解重要)
  2. 你见过的最全面的Python重点知识汇总
  3. 向隐形冠军学习:聚焦人效,用时间管理提效益
  4. crm系统用什么语言写的_什么是CRM系统以及如何正确选择
  5. NOIP2003 第二题 侦探推理 ——论世界上最逗比的出(da)题(shei)人(bi)
  6. PLook——记录你的知识
  7. PyQt如何使界面按钮更加美观
  8. 如何应付全英文的技术面试(三)
  9. 整型数组处理算法(十一)请实现一个函数:线段重叠(性能优化)。[风林火山]
  10. 线段拟合(带拉格朗日乘子,HGL)