bthread源码分析(七)bthread调度逻辑

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)

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值