In preview of Visual Studio 2015, we introduced Coroutines for C++, see these blog post for an introduction and here.
You can also look at the CPPCon 2015 talk about C++ Coroutines here.
We continue to work on resumable functions, here it is a brief update on coroutines status in VS 2015 Update 1. See the Visual Studio 2015 Update1 post here.
Some limitations are gone:
- Now supported on ARM, x86 and amd64
- Now you can use exceptions in a coroutine
- Now you can use return statement before await or yield in a coroutine
- Now you can use coroutines with /ZI (Edit and Continue Debugging)
Some stayed:
- Still not compatible with /sdl and /RTCx flags (should fix in VS Update 2)
- We will give incorrect /W4 warnings about variables being unused or uninitialized in the coroutines
Design changes tracking the latest coroutine proposal (P0057):
- Initial_suspend/final_suspend/yield_value must return awaitable
- Allocation customization is done by overloading operator new of the promise rather than providing an allocator object
- Await customization via operator await
- yield is now expression, not a statement
- (see P0054 for more details)
What to expect in VS Update 2
- Removal of the limitations
- Adding coroutine specific optimizations
- await_transform customizaiton point (see P0054)
- Adding the Kona 2015 keywords: co_await, co_yield and co_return.
References
- P0054: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0054r0.html
P0057: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0057r0.pdf
CppCon Coroutine talk: https://www.youtube.com/watch?v=_fu0gx-xseY
Bonus
Use operator await to define how to await on std::chrono::duration that goes straight to Win32 threadpool APIs.
#include <windows.h>
#include <future>
#include <iostream>
auto operator await(std::chrono::sys tem_clock::duration duration) {
class awaiter {
static void CALLBACK 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::duration d) : 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); }
};
return awaiter{ duration };
}
using namespace std;
using namespace 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”;
}
0 comments