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";

}