VS2015 Update 1中的协同程序
[原文发表地址] Coroutines in Visual Studio 2015 - Update 1
[原文发表时间] 2015/11/30 8:51 AM
在 Visual Studio 2015的预览版本中,我们为C++引进了协同程序这个概念,你可以在这里和一些博客中看到相关介绍。也可以观看2015 CPPCon 上关于C++协同程序的讨论视频。
我们当前的工作重点仍然是Resumable功能,这篇文章只是简单更新一下协同程序在VS 2015 Update1上的状态。VS2015 Update 1发布内容详见这里。
取消的一些限制:
· 现在ARM, x86 和amd64上支持协同程序
· 现在协同程序支持异常处理
· 现在协同程序在await或者yield之前可使用return语句
· 现在协同程序可同/ZI选项一起使用(编辑并且继续调试)
仍存在的缺陷:
· 不兼容/sdl和/RTCx(会在VS Update 2上修复)
· 关于协同程序中变量未使用或者未被初始化时,我们给出/W4警告是不准确的;
追踪最新的协同程序提议所做的更改设计( P0057):
· Initial_suspend,final_suspend和yield_value必须返回awaitable
· 通过重载promise 的operator new而不是提供一个分配器对象来实现配置定制化
· 通过operator await可以自定义Await
· Yield不是一个语句而是一个表达式
· (更多详情请见P0054)
期待在VS Update 2上的实现:
· 修复存在的缺陷
· 对协同程序的特性进行优化
· 有关await_transform 自定义的相关意见(详情见P0054)
· 添加Kona 2015 关键字:co_yield和co_return
参考文献:
· P0054: https://www.openstd.org/jtc1/sc22/wg21/docs/papers/2015/p0054r0.html
· P0057: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0057r0.pdf
· CppCon 上关于协同程序的讨论:https://www.youtube.com/watch?v=_fu0gx-xseY
示例程序:
使用operator await 在std::chrono::duration上定义如何使用await, 这可以直接应用在Win32 threadpool APIs。
#include<windows
#include<future>
#include<iostream>
autooperator await(std::chrono::system_clock::durationduration) {
classawaiter {
staticvoidCALLBACK TimerCallback(PTP_CALLBACK_INSTANCE, void *Context, PTP_TIMER) {
std::experimental::coroutine_handle<>::from_address(Context)();
}
PTP_TIMER timer = nullptr;
std::chrono::system_clock::duration duration;
public:
explicit awaiter(std::chrono::system_clock::durationd) : duration(d) {}
bool await_ready() const { return duration.count() <= 0; }
bool await_suspend(std::experimental::coroutine_handle<> resume_cb) {
int64_t relative_count = -duration.count();
timer = CreateThreadpoolTimer(TimerCallback, resume_cb.to_address(), nullptr);
SetThreadpoolTimer(timer, (PFILETIME)&relative_count, 0, 0);
return timer != 0;
}
void await_resume() {}
~awaiter() { if (timer) CloseThreadpoolTimer(timer); }
};
returnawaiter{ duration };
}
usingnamespace std;
usingnamespace std::chrono;
future<void> test() {
cout << this_thread::get_id() <<": sleeping...\n";
await 1ms;
cout << this_thread::get_id() <<": woke up\n";
}
int main() {
test().get();
cout << this_thread::get_id() <<": back in main\n";
}