[Windows翻译]取消一个Windows Runtime异步操作,第8部分。C++/WinRT,修订版

159 阅读1分钟

原文地址:devblogs.microsoft.com/oldnewthing…

原文作者:devblogs.microsoft.com/oldnewthing…

发布时间:2020年7月10日

前段时间,我们观察到,C++/WinRT依靠GetResults()方法的ABI结果来报告取消。这与C#和C++/CX中任务取消的预测方式不同。此外,这是一个泄漏的抽象。等待的代码需要知道底层操作是如何实现的,才能知道取消时将引发什么异常。

幸运的是,这一点在PR 643中已经得到了修正(发布的版本是2.0.200601.2),因此C++/WinRT在处理取消的方式上与其他的预测一致。现在它通过检查操作的状态来检测取消。

从概念上讲,这只是一个单行修复。

template <typename Async>
struct await_adapter
{
    ...

    auto await_resume() const
    {
        if (async.Status() == AsyncStatus::Canceled) throw hresult_canceled();
        return async.GetResults();
    }
};

然而,这将虚拟方法调用async.Status()添加到热代码路径中。更糟糕的是,如果这是一个远程操作,虚拟方法调用必须跨越一个进程边界,这就更加昂贵了。如果你启用了Async-Async,那么这就变成了一个本地查询,但它仍然是虚拟的)。

解决的办法是缓存Completed回调报告的状态。

inline void check_status_canceled(AsyncStatus status)
{
    if (status == AsyncStatus::Canceled) throw hresult_canceled();
}

template <typename Async>
struct await_adapter
{
    AsyncStatus status = AsyncStatus::Started;
    ...

    void await_suspend(std::experimental::coroutine_handle<> handle)
    {
        async.Completed([this, handler = disconnect_aware_handler{ handle }]
                        (auto&&, auto&& operation_status)
        {
            status = operation_status;
            handler();
        });
    }

    auto await_resume() const
    {
        check_status_canceled(status);
        return async.GetResults();
    }
};

将Canceled状态转换为异常的代码被剔除,因为需要对其他对操作结果做出反应的方法进行类似的修正。


www.deepl.com 翻译