Async cancellation bridge between coroutine and synchronous code
@jonwis is already working on this.
Since Nov 30, 2023.
- Dominant language
- C++
- Stars
- 3k
- Forks
- 300
- Avg merge
- 19h 12m
- Merged PRs (30d)
- 1
Description
We have code that takes a shared_ptr<bool> as a "cancel marker" for when an outer IAsyncOperation calls an inner long-running-but-non-async method, like this:
winrt::IAsyncOperation<winrt::hstring> GetStringOfManyThingsAsync() {
auto lifetime{get_strong()};
auto sharedCancel = std::make_shared<bool>(false);
auto canceltoken = co_await winrt::get_cancellation_token();
canceltoken.enable_propagation(); // not _strictly_ necessary since this does not await anything else
canceltoken.callback([sharedCancel] { *sharedCancel = true; });
co_await winrt::resume_background();
auto moreThings = CallOtherCodeSynchronously(..., sharedCancel);
co_return StringFromMoreThigns(moreThings);
}
auto CallOtherCodeSynchronously(auto... std::shared_ptr<bool> cancelToken) {
for (int i = 0; i < 200 && !*cancelToken; ++i) {
DoSlowThing();
}
return ...;
}
It'd be neat if instead we could say this:
winrt::IAsyncOperation<winrt::hstring> GetStringOfManyThingsAsync() {
auto lifetime{get_strong()};
auto canceltoken = co_await wil::get_shared_cancellation_token();
canceltoken.enable_propagation(); // not _strictly_ necessary since this does not await anything else
co_await winrt::resume_background();
auto moreThings = CallOtherCodeSynchronously(..., canceltoken);
co_return StringFromMoreThigns(moreThings);
}
auto CallOtherCodeSynchronously(auto... std::shared_ptr<bool> cancelToken) {
for (int i = 0; i < 200 && !*cancelToken; ++i) {
DoSlowThing();
}
return ...;
}
Or maybe instead we say this:
auto canceltoken = co_await winrt::get_cancellation_token();
auto sharedCanceller = wil::make_shared_cancel(canceltoken);
... where sharedCanceller is basically this:
struct shared_cancel_token
{
bool m_canceled{false};
void cancel() { m_canceled = true; }
bool is_canceled() const { return m_canceled };
}
template<typename Q> std::shared_ptr<shared_cancel_token> make_shared_cancel(Q& outerToken)
{
auto t = std::make_shared<shared_cancel_token>();
outerToken.callback([t] { t->cancel(); };
return t;
}
And then code passes around the shared_cancel_token instead of the shared_ptr. Then we could also do things like hang a wait() off of that using WaitOnAddress (expanding the size of m_canceled to be a pointer) or expose an event handle for use with WFMO.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.