金融审核网站制作,企业官网用什么系统,wordpress主题中文乱码,深圳宝安区怎么样前言
前面两节我们已经能够实现一个可用的协程框架了。但我们一定还想更深入的了解协程#xff0c;于是我们就想尝试下能不能co_await一个协程。下面会涉及到部分模板编程的知识#xff0c;主要包括#xff08;模板偏特化#xff0c;模板参数列表传值#xff0c;模板函数…前言
前面两节我们已经能够实现一个可用的协程框架了。但我们一定还想更深入的了解协程于是我们就想尝试下能不能co_await一个协程。下面会涉及到部分模板编程的知识主要包括模板偏特化模板参数列表传值模板函数类型推断可以提前了解下方便后续理解。
在开始之前我们不妨思考下面一些问题 异步函数 和 协程 在co_await时的共性是什么 两者的操作数都必须是awaiter这意味着co_await协程,必须能够将协程转换为一个awaiter。协程生命周期什么时候结束协程执行到co_return时或者执行coroutine_handle.destory()时以及出现未捕获的异常时会销毁协程释放协程对象promise协程从开始到结束会产生几个awaiter会co_awiter几次 2~3次initial_suspend和final_suspend会产生两个awaiter同时编译器帮我们进行了co_await 还有一次是人为的co_await,即我们co_await一个协程。initial_suspend和final_suspend 这两个功能的作用是什么 为什么要initial_suspend和final_suspend 或者说为什么这里可以自由返回可挂起的等待体为什么提供这个机制initial_suspend是协程创建后编译器帮我们co_await这将允许我们即使不使用co_await协程函数运行能参与到不同于普通函数的调度中这直接决定了协程行为上和普通函数的相似程度;final_suspend功能也类似我们已经知道该函数是在协程执行结束时操作系统使用co_await调用的如果final_suspend返回的是不挂起操作awaiter那么协程在执行完后会自动析构promise对象释放资源而返回挂起awaiter提供了将协程对象销毁交给用户的协程调度器的可能性。这里还有一个知识点是对第二篇final_suspend的补充使用协程还可以实现序列发生器序列发生器中的协程永远不会调用co_return所以永远不会结束当final_suspend不挂起时编译器也无法分辨出一个协程的生命周期而这里选择挂起我们可以明确告诉编译器该协程会结束有助于编译器帮我们优化。 协程代码实现
我的目标是让c像在python中一样使用协程。 我的协程实现思路如下我希望协程表现出的行为尽可能和普通函数一样所以我不在initial_suspend时挂起协程给协程调度器调度我直接在该返回的awaiter::await_ready返回true给编译器提供优化协程为inline的机会协程应该是和python一样是单线程所以不会在用户co_await时交给其他线程处理这部分功能由上一节异步函数补齐我希望编译器尽可能能帮我优化代码而且更符合规范所以我在协程结束时挂起协程交给调度器去调度销毁。
代码
#include coroutine
#include future
#include chrono
#include iostream
#include queue
#include thread
#include mutex
#include memory
#include vectorstruct async_task_base
{virtual void completed() 0;virtual void resume() 0;
};std::mutex m;
std::vectorstd::shared_ptrasync_task_base g_event_loop_queue; std::vectorstd::shared_ptrasync_task_base g_resume_queue; //多线程异步任务完成后后待主线程恢复的线程
std::vectorstd::shared_ptrasync_task_base g_work_queue; //执行耗时操作线程队列enum class EnumAwaiterType:uint32_t{EnumInitial 1, //协程initialEnumSchduling 2,// 用户co_awaitEnumFinal 3//销毁
};template typename ReturnType
struct CoroutineTask;template typename CoTask, EnumAwaiterType AwaiterType
struct CommonAwaiter ;template typename CoTask, EnumAwaiterType AwaiterType
struct coroutine_task: public async_task_base{coroutine_task(CommonAwaiterCoTask, AwaiterType awaiter):owner_(awaiter){}void completed() override{}void resume() override{if(owner_.h_.done()){owner_.h_.destroy();}else{owner_.h_.resume();}}CommonAwaiterCoTask,AwaiterType owner_ ;
};template typename CoTask, EnumAwaiterType AwaiterType EnumAwaiterType::EnumSchduling
struct CommonAwaiter
{using return_type typename CoTask::return_type;using promise_type typename CoTask::promise_type;CommonAwaiter(promise_type* promise):promise_(promise){}// 当时initial_suspend返回的awaiter时挂起直接resumebool await_ready() const noexcept { return false;}//也可以直接恢复 // std::coroutine_handle await_suspend(std::coroutine_handle h) {// return h;// }void await_suspend(std::coroutine_handle h) {// std::cout await_suspend() std::endl;h_ h;g_event_loop_queue.emplace_back(std::shared_ptrasync_task_base( new coroutine_taskCoTask, AwaiterType(*this)) );}return_type await_resume() const noexcept { return promise_-get_value();}~CommonAwaiter(){}bool resume_ready_ false;promise_type* promise_ nullptr;std::coroutine_handle h_ nullptr;
};template typename CoTask
struct CommonAwaiterCoTask, EnumAwaiterType::EnumInitial
{CommonAwaiter(){}// 当时initial_suspend返回的awaiter时挂起跳过await_suspend直接resume,跳过bool await_ready() const noexcept { return true;}void await_suspend(std::coroutine_handle) {}void await_resume() const noexcept { }~CommonAwaiter(){}
};// 必须为noexcept因为这个时候协程已经运行结束不该有异常产生
template typename CoTask
struct CommonAwaiter CoTask, EnumAwaiterType::EnumFinal
{CommonAwaiter(){}// 这里不选择true让编译器帮我们自动释放,如果为true编译器不知道什么时候协程结束无法帮助我们优化bool await_ready() noexcept { return false;}void await_suspend(std::coroutine_handle h) noexcept{h_ h;g_event_loop_queue.emplace_back(std::shared_ptrasync_task_base( new coroutine_taskCoTask, EnumAwaiterType::EnumFinal(*this)));}// 无需返回void await_resume() noexcept{ }std::coroutine_handle h_ nullptr;
};templatetypename CoTask
struct Promise
{using return_type typename CoTask::return_type ;~Promise(){// std::cout ~Promise std::endl;}CommonAwaiterCoTask, EnumAwaiterType::EnumInitial initial_suspend() {return {}; };CommonAwaiterCoTask, EnumAwaiterType::EnumFinal final_suspend() noexcept { return {}; }// 提供了一种对协程中未捕获的异常的再处理比如将异常保存下来实现协程如以下形式 coroutine().get().catch()// 这里我们的实现形式决定了这里直接再次抛出异常就好void unhandled_exception(){// try {std::rethrow_exception(std::current_exception());// } catch (const std::exception e) {// // 输出异常信息// std::cerr Unhandled exception caught in CustomAsyncTask: e.what() std::endl;// } catch (...) {// std::cerr Unhandled unknown exception caught in CustomAsyncTask! std::endl;// }}CoTask get_return_object(){ return CoTask(this);}return_type get_value() {return value_;}void return_value(return_type value){value_ value;}// 该代码写在Promise中的好处是可以方便阅读代码很容易就能回想出协程最多会返回三个等待体templatetypename TCommonAwaiterCoroutineTaskT await_transform(CoroutineTaskT task){return CommonAwaiterCoroutineTaskT(task.p_);}CoTask await_transform(CoTask task){return CommonAwaiterCoTask(task.p_);}return_type value_;
};template typename ReturnType
struct CoroutineTask{using return_type ReturnType;using promise_type PromiseCoroutineTask;CoroutineTask(const CoroutineTask other) delete;CoroutineTask(const CoroutineTask other) delete;CoroutineTask operator(const CoroutineTask) delete;CoroutineTask operator(const CoroutineTask) delete;CoroutineTask(promise_type* promise) {p_ promise;}promise_type *p_ nullptr;};CoroutineTasku_int64_t second_coroutine(){co_return 3;
}CoroutineTaskfloat third_coroutine(){co_return 3.1;
}CoroutineTaskchar first_coroutine(){uint64_t num co_await second_coroutine();std::cout second_coroutine result is : num std::endl; float num2 co_await third_coroutine();std::cout third_coroutine result is : num2 std::endl; co_return b;
}void do_work() {while (1){std::lock_guardstd::mutex g(m);for(auto task : g_work_queue){task-completed();g_resume_queue.push_back(task);}g_work_queue.clear();} }void run_event_loop(){std::vectorstd::shared_ptrasync_task_base g_raw_work_queue_tmp;std::vectorstd::shared_ptrasync_task_base g_event_loop_queue_temp;while(1){g_raw_work_queue_tmp.clear();g_event_loop_queue_temp.clear();{g_event_loop_queue_temp.swap(g_event_loop_queue);std::lock_guardstd::mutex g(m);g_raw_work_queue_tmp.swap(g_resume_queue);}// 优先恢复耗时任务for(auto task : g_raw_work_queue_tmp){task-resume();}for(auto task : g_event_loop_queue_temp){task-resume();}}
}void test_func(){first_coroutine();
}int main(){test_func();std::thread work_thread(do_work);run_event_loop();return 0;
}
代码分析
Promise unhandled_exception
unhandled_exception 的作用是是用来对协程中未捕获的异常再处理。在一些实现协程使用方式为 **coroutine().get().catch()**的架构中会把未捕获的异常暂存下来待恢复的时候再抛出。我选择直接抛出异常因为出现未捕获的异常时协程也会提前结束这时reume的结果是未定义的所以我觉得在resume之前抛出异常有有必要的。 await_transform
await_transform的作用和重载运算符co_await是一样的在co_await一个协程时会转换CoroutineTask为一个awaiter。使用await_transform的优势是所有等待体的返回时机都在promise定义出来方便代码阅读。 这里我们需要注意的是该await_transform需要定义为模板函数而不能用Promise的类型参数CoTask作为传入参数类型。
修改代码如下 编译一下我们发现报错了 这里我们再结合代码理解下 根据报错信息和调用顺序我们可以得出以下结论 当前位于CoroutineTask的写成体中所以对应的promise类型是promiseCoroutineTask, 这时实例化的await_transform 实际上是 CoroutineTask await_transform (CoroutineTasktask)而这时await_transform 操作的是协程second_coroutine协程类型是CoroutineTasku_int64_t 类型不一致所以会出现上面的报错。 CoroutineTask 协程类CoroutineTask要保存什么 这里只保存了promise的指针原因如下: 协程和用户代码交互是通过awaiter对象由于返回值是通过return_value保存在协程promise中的我们需要在awaiter从promise获取返回的值所以需要在awaiter中保存promise的指针那promise的指针从哪来呢awaiter是在await_transform中使用CoroutineTask初始化的而我们又知道CoroutineTask是由promise 调用 get_return_object创建的。所以我们在创建CoroutineTask时将promise的指针保存进去 这样awaiter就能够通过CoroutineTask作为中介得到promise的指针啦 CommonAwaiter
其实讲到这里CommonAwaiter就没多少能讲的东西了。 awaiter使用偏特化根据不同枚举特化了三个版本。来控制协程的基本行为即创建时不挂起能够有机会被编译器优化为inline用户代码挂起能够返回任意co_return返回的值结束挂起参与调度销毁。对了还有一个问题协程句柄为什么保存在awaiter中而不是promise中。在我看来awaiter就代表了每个挂起点所以将couroutine_handle保存在awaiter中couroutine_handle很小所以不考虑内存开销
运行结果
最后我们运行下代码完美运行。 这里就不阐述流程了下一篇会将二、三两节的代码合并起来集中阐述下流程和汇总下重要的知识点。 文章转载自: http://www.morning.xkqjw.cn.gov.cn.xkqjw.cn http://www.morning.tymnr.cn.gov.cn.tymnr.cn http://www.morning.nhdw.cn.gov.cn.nhdw.cn http://www.morning.ztcwp.cn.gov.cn.ztcwp.cn http://www.morning.hhqtq.cn.gov.cn.hhqtq.cn http://www.morning.plqqn.cn.gov.cn.plqqn.cn http://www.morning.wklyk.cn.gov.cn.wklyk.cn http://www.morning.hsxkq.cn.gov.cn.hsxkq.cn http://www.morning.ysybx.cn.gov.cn.ysybx.cn http://www.morning.pyzt.cn.gov.cn.pyzt.cn http://www.morning.kfclh.cn.gov.cn.kfclh.cn http://www.morning.pxbky.cn.gov.cn.pxbky.cn http://www.morning.htbsk.cn.gov.cn.htbsk.cn http://www.morning.cctgww.cn.gov.cn.cctgww.cn http://www.morning.xjqkh.cn.gov.cn.xjqkh.cn http://www.morning.cjqqj.cn.gov.cn.cjqqj.cn http://www.morning.tstwx.cn.gov.cn.tstwx.cn http://www.morning.cgtrz.cn.gov.cn.cgtrz.cn http://www.morning.cczrw.cn.gov.cn.cczrw.cn http://www.morning.mkyxp.cn.gov.cn.mkyxp.cn http://www.morning.rhkgz.cn.gov.cn.rhkgz.cn http://www.morning.hdscx.cn.gov.cn.hdscx.cn http://www.morning.txltb.cn.gov.cn.txltb.cn http://www.morning.kzbpx.cn.gov.cn.kzbpx.cn http://www.morning.lbbgf.cn.gov.cn.lbbgf.cn http://www.morning.nptls.cn.gov.cn.nptls.cn http://www.morning.yxgqr.cn.gov.cn.yxgqr.cn http://www.morning.gwhjy.cn.gov.cn.gwhjy.cn http://www.morning.kfcz.cn.gov.cn.kfcz.cn http://www.morning.zzgkk.cn.gov.cn.zzgkk.cn http://www.morning.gagapp.cn.gov.cn.gagapp.cn http://www.morning.lrplh.cn.gov.cn.lrplh.cn http://www.morning.yrbp.cn.gov.cn.yrbp.cn http://www.morning.rlnm.cn.gov.cn.rlnm.cn http://www.morning.yfmwg.cn.gov.cn.yfmwg.cn http://www.morning.wslr.cn.gov.cn.wslr.cn http://www.morning.ypmqy.cn.gov.cn.ypmqy.cn http://www.morning.plpqf.cn.gov.cn.plpqf.cn http://www.morning.ndpzm.cn.gov.cn.ndpzm.cn http://www.morning.zlmbc.cn.gov.cn.zlmbc.cn http://www.morning.dtlnz.cn.gov.cn.dtlnz.cn http://www.morning.pbwcq.cn.gov.cn.pbwcq.cn http://www.morning.wsjnr.cn.gov.cn.wsjnr.cn http://www.morning.cmfkp.cn.gov.cn.cmfkp.cn http://www.morning.wmnpm.cn.gov.cn.wmnpm.cn http://www.morning.nicetj.com.gov.cn.nicetj.com http://www.morning.bppml.cn.gov.cn.bppml.cn http://www.morning.tdxlj.cn.gov.cn.tdxlj.cn http://www.morning.rzrbw.cn.gov.cn.rzrbw.cn http://www.morning.rcjqgy.com.gov.cn.rcjqgy.com http://www.morning.bkslb.cn.gov.cn.bkslb.cn http://www.morning.spftz.cn.gov.cn.spftz.cn http://www.morning.fbjqq.cn.gov.cn.fbjqq.cn http://www.morning.kwfnt.cn.gov.cn.kwfnt.cn http://www.morning.hhxpl.cn.gov.cn.hhxpl.cn http://www.morning.ktskc.cn.gov.cn.ktskc.cn http://www.morning.sfzwm.cn.gov.cn.sfzwm.cn http://www.morning.xqmd.cn.gov.cn.xqmd.cn http://www.morning.shprz.cn.gov.cn.shprz.cn http://www.morning.nytpt.cn.gov.cn.nytpt.cn http://www.morning.njstzsh.com.gov.cn.njstzsh.com http://www.morning.zqsnj.cn.gov.cn.zqsnj.cn http://www.morning.kgmkl.cn.gov.cn.kgmkl.cn http://www.morning.sfphz.cn.gov.cn.sfphz.cn http://www.morning.ytmx.cn.gov.cn.ytmx.cn http://www.morning.niukaji.com.gov.cn.niukaji.com http://www.morning.czxrg.cn.gov.cn.czxrg.cn http://www.morning.ndmh.cn.gov.cn.ndmh.cn http://www.morning.csgwd.cn.gov.cn.csgwd.cn http://www.morning.youprogrammer.cn.gov.cn.youprogrammer.cn http://www.morning.hrqfl.cn.gov.cn.hrqfl.cn http://www.morning.gtcym.cn.gov.cn.gtcym.cn http://www.morning.ngjpt.cn.gov.cn.ngjpt.cn http://www.morning.bmqls.cn.gov.cn.bmqls.cn http://www.morning.lszjq.cn.gov.cn.lszjq.cn http://www.morning.gtqws.cn.gov.cn.gtqws.cn http://www.morning.tdmgs.cn.gov.cn.tdmgs.cn http://www.morning.qbnfc.cn.gov.cn.qbnfc.cn http://www.morning.fnpmf.cn.gov.cn.fnpmf.cn http://www.morning.zpzys.cn.gov.cn.zpzys.cn