原文地址:devblogs.microsoft.com/oldnewthing…
原文作者:devblogs.microsoft.com/oldnewthing…
发布时间:2020年4月7日
上一次,我们看到你可以使用ICallbackContext在另一个公寓中从你的委托人那里同步运行代码,如果调用你的委托人的代码依赖于你的返回时机,这一点很重要。
我们也可以用一个同步运行的coroutine的形式来表达。
如果我们让 await_suspend 同步调用句柄,那么这个coroutine 的延续就会和调用 co_await 的代码同步运行。
auto resume_synchronous(ICallbackContext* context)
{
struct awaiter : std::experimental::suspend_always
{
ICallbackContext* context;
bool await_suspend(
std::experimental::coroutine_handle<> handle)
{
InvokeInContext(context, handle);
return true;
}
};
return awaiter{ context };
}
这简化了委托人,让你使用co_await来做脏活。
deviceWatcher.Added(
[=, context = CaptureCurrentApartmentContext()]
(auto&& sender, auto&& info) -> winrt::fire_and_forget
{
co_await resume_synchronous(context.Get());
viewModel.Append(winrt::make<DeviceItem>(info));
});
即使有co_await,执行也会同步进行,因为 await_suspend是同步运行连续的。
co_await是否同步恢复¹由等待者决定。如果你co_await的东西其waiter异步恢复,那么co_await将异步恢复。
deviceWatcher.Added(
[=, context = CaptureCurrentApartmentContext()]
(auto&& sender, auto&& info) -> winrt::fire_and_forget
{
auto original_context = CaptureCurrentApartmentContext();
co_await resume_synchronous(context.Get());
viewModel.Append(make<DeviceItem>(info));
co_await resume_synchronous(original_context.Get());
more_stuff();
auto result = co_await GetMoreDataAsync();
process_result(result);
});
在上面的例子中,前两个co_await是同步的,但是第三个(co_await GetMoreDataAsync())大概是异步的。这意味着委托人将在第三个co_await点返回,当coroutine恢复时,引用参数(sender和info)可能不会有效。
¹或者根本就不存在。内置的 awaiter suspend_always 暂停,永远不会被唤醒。