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();
}