前言
这是c++协程实现第二篇,这里开始我们将开始真正意义上开始实现协程。对协程基础流程不清楚的,可以看我的第一篇。 后续可能需要一定的模板知识,可以看下我的模板的文章,那些知识就完全够用了。本篇将实现一个协程封装的异步任务队列,即一个耗时任务到其他线程完成后,继续恢复执行流。在这里你可以看到如何通过协程去回调。下面就直接开始吧。
协程实现
上一篇我们已经谈过,协程最大的一个好处就是去回调。在工程中,我们往往因为效率,而选择异步接口,或者不希望堵塞任务线程,而将某些耗时任务丢到线程池中执行,我们往往需要传入一个回调,待耗时任务完成后,调用来执行后续操作,但回调的引入,割裂了代码逻辑,大大加重了对业务的理解难度,以及修改流程的难度,在工程中我就深受其害。直接上代码。
代码
#include <coroutine>
#include <future>
#include <chrono>
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <memory>
#include <vector>
struct async_task_base
{
virtual void completed() = 0;
virtual void resume() = 0;
};
std::mutex m;
std::vector<std::shared_ptr<async_task_base>> g_resume_queue; //原来的 eventloop队列
std::vector<std::shared_ptr<async_task_base>> g_work_queue; //执行耗时操作线程队列
template <typename T>
struct AsyncAwaiter;
using namespace std::chrono_literals;
struct suspend_always
{
bool await_ready() const noexcept {
try
{
std::cout << "suspend_always::await_ready" << std::endl;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
return false;
}
void await_suspend(std::coroutine_handle<> handle) const noexcept {
try
{
std::cout << "suspend_always::await_suspend" << std::endl;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
}
void await_resume() const noexcept {
try
{
std::cout << "suspend_always::await_resume" << std::endl;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
}
};
struct suspend_never
{
bool await_ready() const noexcept {
try
{
std::cout << "suspend_never::await_ready" << std::endl;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
return true;
}
void await_suspend(std::coroutine_handle<> handle) const noexcept {
try
{
std::c