Search code examples
uwpwindows-runtimec++-winrt

Unclear how to use winrt::get_cancellation_token for IAsyncAction


I'm trying to write a coroutine-based background thread in C++/WinRT that loops on the status of a cancellation token, because I need to take some cleanup action on cancellation.

I'm trying to follow the documentation on MSDN (https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/concurrency#canceling-an-asychronous-operation-and-cancellation-callbacks) but an adaptation of the sample code doesn't compile, and the cancellation_token_t type doesn't appear to be callable.

void BackgroundThreadManager::Start()
{
    this->m_Thread = this->RunAsync();
}

void BackgroundThreadManager::Stop()
{
    if (this->m_Thread)
    {
        m_Thread.Cancel();
        m_Thread = nullptr;
    }
}

IAsyncAction BackgroundThreadManager::RunAsync()
{
    winrt::resume_background();
    auto token{ winrt::get_cancellation_token() };
    while (!token())
    {
        co_await this->DoSomethingAsync();
    }
    co_await this->DoSomeCleanupAsync();
}

Unfortunately, this fails to compile with "error C2064: term does not evaluate to a function taking 0 arguments" referring to the "while (!token())" line.

Code agrees with this, as the definition (in base.h) of get_cancellation_token_t is

struct get_cancellation_token_t {};

I'm guessing I'm doing something wrong fundamentally, or the MSDN documentation is out of date. Any clues? Thanks!


Solution

  • You're forgetting to co_await on the get_cancellation_token() expression. The co_await provides the hook that the library needs to reach in and get the IAsyncAction instance that may be canceled. By the way, you also forgot to co_await the resume_background() expression.

    Also, note that coroutines are also automatically canceled at suspension points (co_await), so it may be better to use a cancellation callback to ensure that your cancellation logic isn't overlooked.