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!
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.