Lab1 实验解析

tinyCoroLab1 实验解析

⚠️tinyCoroLab 的实验强烈推荐实验者独自完成而非直接翻阅实验解析,否则这与读完题直接翻看参考答案无太大区别,实验解析仅供实验者参考。

本节将会以 tinyCoroLab 的官方实现tinyCoroarrow-up-right为例,为大家分析并完成 lab1,请实验者预先下载 tinyCoro 的代码到本地。

git clone https://github.com/sakurs2/tinyCoro

并打开include/coro/task.hpparrow-up-right并大致浏览代码结构。

📖lab1 任务参考实现

🧑‍💻Task #1 - 实现 task 执行结束后的正确调度逻辑

要想实现任务目标中的调度逻辑,核心便是建立协程调用之间的互联关系,即让被调用协程可以感知到调用协程,这样在被调用协程执行完成后才可以正确转移执行权到用协程,这样就形成了正确的嵌套调用关系,那么如何建立协程调用之间的互联关系呢?

tinyCoro 为 promise_base 添加了m_continuation成员用于表示协程的父级调用协程的句柄以及用于设置该成员的函数continuation,定义如下:

struct promise_base
{
    std::coroutine_handle<> m_continuation{nullptr};
    auto continuation(std::coroutine_handle<> continuation) noexcept -> void { m_continuation = continuation; }
};

那么什么时候调用continuation函数呢?在 task 内部存在结构体awaitable_base作为 task 被 co_await 调用时返回的 awaiter,这通过重载 co_await 运算符来实现,实验者应该不难理解awaitable_baseawait_suspend函数的参数是调用协程的句柄,因为awaitable_base是在被调用协程对 co_await 重载后的函数内被返回,所以本身可以持有被调用协程的句柄,那么此时获取被调用协程的 promise 并调用函数continuation,参数即awaitable_baseawait_suspend的参数。

此时已经为调用和被调用协程建立互联关系了,下一步就是如何使用互联关系。tinyCoro 添加了结构体final_awaitable作为final_suspend的返回值,定义如下:

final_awaitable通过在await_suspend中获取 promise 的m_continuation来决定执行权的转移,如果m_continuation非空即存在父调用协程,然后转移执行权。

💡当await_suspend返回std::noop_coroutine()时执行权如何转移呢? 在预备知识章节已经讲过了哦!

Task #2 - 为 task 添加 detach 状态

状态是需要被存储的,所以 tinyCoro 为 promise_base 添加了一个状态成员以及与状态相关的成员函数:

对于 task 的detach函数,对其关联的 promise 设置状态就可以了,并且移除自身持有的协程句柄,代码如下:

而负责协程资源清理的clean函数,只要判断协程是否为 detach 状态,是则释放资源:

实验总结

  • 通过完成协程的嵌套调用对协程执行权转移以及如何利用 awaiter 转移有了更深的理解

  • 通过完成 task 的 detach 状态学习到了如何正确处理协程持有的资源避免产生内存安全问题

Last updated