Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async timeout support for C++/WinRT #341

Merged
merged 5 commits into from Apr 23, 2019
Merged

Async timeout support for C++/WinRT #341

merged 5 commits into from Apr 23, 2019

Conversation

kennykerr
Copy link
Contributor

@kennykerr kennykerr commented Apr 23, 2019

Today C++/WinRT provides support for blocking wait via async.get() and cooperative wait via co_await async but there is not ability to use a timeout. This has lead some teams needing timeout support to implement various workarounds that are not very efficient or robust. Part 1 introduces support for a timeout for the blocking scenario. Part 2 introduces support for cooperative timeout for coroutines.

The get function follows the pattern established by std::future so it makes sense to adopt future's wait_for function to support a timeout as well. Note that WinRT only allows waiting once. That means you cannot use wait_for in a loop, or any other scenario where multiple waits would occur.

You can wait for an IAsyncAction as follows:

using namespace Windows::Foundation;

IAsyncAction async = ...

if (async.wait_for(5s) == AsyncStatus::Completed)
{
    puts("done");
}

You can wait for an IAsyncOperation as follows:

IAsyncOperation<hstring> async = ...

if (async.wait_for(5s) == AsyncStatus::Completed)
{
    printf("result: %ls\n", async.get().c_str());
}

Or more comprehensively:

IAsyncOperation<hstring> async = ...

switch (async.wait_for(2s))
{
case AsyncStatus::Completed:
    printf("result: %ls\n", async.get().c_str());
    break;
case AsyncStatus::Started:
    puts("still running");
    break;
case AsyncStatus::Canceled:
    puts("canceled");
    break;
case AsyncStatus::Error:
    puts("failed");
    break;
}

}
auto wait_for(Windows::Foundation::TimeSpan const& timeout) const
{
return impl::wait_for(static_cast<Windows::Foundation::IAsyncAction const&>(static_cast<D const&>(*this)), timeout);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

impl:: [](start = 19, length = 6)

needed for disambiguation with current wait_for? (not used on wait_get)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. wait_for calls impl::wait_for but get calls impl::wait_get so no confusion. I didn't want to call it impl::get and rather had the handful of impl functions start with wait_xxx for clarity.

Copy link
Member

@Scottj1s Scottj1s left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@kennykerr kennykerr merged commit ff688a8 into master Apr 23, 2019
@kennykerr kennykerr deleted the kennykerr-waitfor branch April 23, 2019 16:21
@kennykerr kennykerr changed the title Async timeout support for C++/WinRT - part 1 Async timeout support for C++/WinRT Jul 17, 2019
@cScalpel
Copy link

Thank you for this, kennykerr!!! It is exactly what I was looking for when using SerialDevice! I do have a question regarding my implementation:
After I determine that the AsyncStatus is not completed (no data on serial port when using SerialDevice, DataReader.LoadAsync() and IAsyncOperation.wait_for()) I call the IAsyncOperation.Cancel() function. It seems to work but when I return to make a subsequent DataReader.LoadAsync() call, I get a take_ownership_from_abi exception thrown. How can I perform any additional Async functions on the DataReader object after I cancelled the previous operation?

@kennykerr
Copy link
Contributor Author

@cScalpel Glad you like it! You'll need to check the specific information in the thrown exception to figure out what might be wrong (take_ownership_from_abi is not an exception). Whether you can reuse the object that produced the async object following cancellation depends on the implementation of that API. You might need to create a new DataReader, but I'd first test by wrapping the failing request in a catch block and inspecting the error message. Something like this:

try { ... } catch (hresult_error const& e)
{
    printf("%ls\n", e.message().c_str());
}

In general, we don't have expertise to answer questions about specific APIs. For that, I'd suggest Stack Overflow. Tag the question with c++-winrt or windows-runtime and we'll do our best to respond if we are able.

@cScalpel
Copy link

Will do, the exception was indeed "The operation identifier is not valid." I'll update my question on stackoverflow. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants