[Windows翻译]取消一个Windows Runtime异步操作,第6部分:C++/WinRT生成的异步操作。

487 阅读1分钟

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

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

发布时间:2020年7月8日

上一次,我们了解到C++/WinRT服从于底层异步操作,以它认为合适的方式报告取消。今天,我们来看看异步操作是由C++/WinRT库生成的情况。

当你在一个C++/WinRT异步操作上调用Cancel()时,运行的代码是这样的。

struct promise_base : ...
{
    ...

    void Cancel() noexcept
    {
        winrt::delegate<> cancel;
        {
            slim_lock_guard const guard(m_lock);
            if (m_status == AsyncStatus::Started)
            {
                m_status = AsyncStatus::Canceled;
                cancel = std::move(m_cancel);
            }
        }
        if (cancel)
        {
            cancel();
        }
    }
};

promise过渡到Canceled,如果coroutine已经注册了一个取消回调,它就会被调用。

每当与承诺相关联的coroutine执行co_await时,await_transform就会启动(抱歉,我还没有解释,但请相信我),这时C++/WinRT库才有机会放弃操作。

template <typename Expression>
Expression&& await_transform(Expression&& expression)
{
    if (Status() == AsyncStatus::Canceled)
    {
        throw winrt::hresult_canceled();
    }
    return std::forward<Expression>(expression);
}

抛出的hresult_canceled异常被捕获到操作中,以便以后重新抛出。

C++/WinRT库也会在coroutine运行到完成时检查是否取消。

struct promise_type final : ...
{
    ...

    void return_void()
    {
        ...
        if (this->m_status == AsyncStatus::Started)
        {
            this->m_status = AsyncStatus::Completed;
        }
        else
        {
            WINRT_ASSERT(this->m_status == AsyncStatus::Canceled);
            this->m_exception = make_exception_ptr(winrt::hresult_canceled());
        }
        ...
    }
};

如果操作已经被取消,那么我们制造一个假的hresult_canceled异常,并将其保存在m_exception中。

所以我们看到,无论操作的取消是由 await_transform 检测到的,还是由 return_void 检测到的(对于产生值的 coroutine,则由 return_value 检测到),我们最终都会在操作中存储一个 hresult_canceled 异常。

而当有人询问异步活动的结果时,又会出现这个异常。

struct promise_type final : ...
{
    ...

    void GetResults()
    {
        ...
        if (this->m_status == AsyncStatus::Completed)
        {
            return;
        }
        this->rethrow_if_failed();
        ...
    }

    void rethrow_if_failed() const
    {
        if (m_status == AsyncStatus::Error || m_status == AsyncStatus::Canceled)
        {
            std::rethrow_exception(m_exception);
        }
    }
};

如果操作被取消了,那么我们就会达到rethrow_if_failed,它重抛捕获的异常,我们前面看到的异常将是一个hresult_canceled。

但是C++/WinRT并不是IAsyncAction和IAsyncOperation对象的唯一来源。下一次,我们将看看另一个主要来源。WRL.


www.deepl.com 翻译