Task协程任务分析

文章目录

Task

本节进行Task协程任务的分析,Task为libgo的调度单位,也就是协程,每次go func()就会创建出一个Task,整个Task类的结构比较简单,我们先来看一下Task的UML类图,分析下整个结构

Task类图:
在这里插入图片描述

我们可以看到Task继承了TSQueueHook和SharedRefObject这两个基类,这两个基类是libgo的基础组件,用来实现队列,无锁队列,引用计数,智能指针等,这些基础组件我们在之后章节再进行分析。

Attribute

我们简单看一下Task的成员变量:

  • state_ :Task运行时的状态,有runnable(可运行),block(阻塞),done(已完成)三种状态,每次创建时默认为runnable可运行态
  • id_ :协程id,用来标识每个协程
  • proc_ :绑定的协程执行器,Task可以在多个执行器中切换
  • ctx_ :为协程的上下文,每次进行协程切换时要保存当时的上下文
  • fn_ :为协程执行的任务
  • eptr_ :为异常指针,可以在执行协程任务时抛出异常给Listener
  • yieldCount_ :为协程切换次数
  • suspendId_ :为协程挂起的标识
   		//协程的运行状态
        TaskState state_ = TaskState::runnable;
        //协程ID
        uint64_t id_;
        //绑定的执行器
        Processer *proc_ = nullptr;
        //协程上下文
        Context ctx_;
        //协程任务
        TaskF fn_;
        //保存exception的指针
        std::exception_ptr eptr_;
        //切换的次数
        uint64_t yieldCount_ = 0;
        //挂起表示
        atomic_t<uint64_t> suspendId_{0};

method

Task构造函数 : 保存要执行的TaskF,构造ctx_协程上下文,将Task::StaticRun函数作为入口函数,this指针为函数的参数


Task::Task(TaskF const& fn, std::size_t stack_size)
    : ctx_(&Task::StaticRun, (intptr_t)this, stack_size), fn_(fn)
{

}

StaticRun :为类的静态成员函数,在c++中使用c风格的API,回调函数只能使用函数指针,无法使用std::function,所以我们将静态成员函数作为回调函数,类对象作为参数,在静态成员函数中再调用类中保存的std::function,类似适配器模式的设计思想(所有计算机领域的问题,都能引入一个中间层来解决,如果解决不了,那就引入两个中间层)

void FCONTEXT_CALL Task::StaticRun(intptr_t vp)
{
    Task* tk = (Task*)vp;
    tk->Run();
}

Run :在本函数中执行任务,并且执行完后将std::function进行析构,并切换至协程调度器

void Task::Run()
{
    auto call_fn = [this]() {
#if ENABLE_DEBUGGER
        if (Listener::GetTaskListener()) {
            Listener::GetTaskListener()->onStart(this->id_);
        }
#endif

        this->fn_();
        this->fn_ = TaskF(); //让协程function对象的析构也在协程中执行

#if ENABLE_DEBUGGER
        if (Listener::GetTaskListener()) {
            Listener::GetTaskListener()->onCompleted(this->id_);
        }
#endif
    };

    if (CoroutineOptions::getInstance().exception_handle == eCoExHandle::immedaitely_throw) {
        call_fn();
    } else {
        try {
            call_fn();
        } catch (...) {
            this->fn_ = TaskF();

            std::exception_ptr eptr = std::current_exception();
            DebugPrint(dbg_exception, "task(%s) catched exception.", DebugInfo());

#if ENABLE_DEBUGGER
            if (Listener::GetTaskListener()) {
                Listener::GetTaskListener()->onException(this->id_, eptr);
            }
#endif
        }
    }

#if ENABLE_DEBUGGER
    if (Listener::GetTaskListener()) {
        Listener::GetTaskListener()->onFinished(this->id_);
    }
#endif
    //协程任务执行完毕
    state_ = TaskState::done;
    //切换至调度器
    Processer::StaticCoYield();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值