In Windows Store Apps, C++(C# is similar though), doing something like
IAsyncAction^ Action = CurrentAppSimulator::ReloadSimulatorAsync(proxyFile);
create_task( Action ).then([this]()
{
}.wait();
results in an unhandled exception. Usually it's
Microsoft C++ exception: Concurrency::invalid_operation at memory location 0x0531eb58
And I kind of need for that action to finish to get my In App Purchase information before trying to use it. The weird thing here is that anything else besides IAsyncAction waits just fine. IAsyncOperation and IAsyncOperationWithProgress worked just fine, but this ? Exception and then crash.
To be honest, I have no idea what's the difference between an IAsyncOperation and an IAsyncAction, they seem similar to me.
UPDATE :
By analyzing this page http://msdn.microsoft.com/en-us/library/vstudio/hh750082.aspx you can figure out that IAsyncAction is just an IAsyncOperation without a return type. But, you can then see that most IAsyncAction-s are waitable. The real problem though is that certain Windows functions just want to execute on a particular thread (for some reason). ReloadSimulatorAsync is one such fine example.
Using code like this :
void WaitForAsync( IAsyncAction ^A )
{
while(A->Status == AsyncStatus::Started)
{
std::chrono::milliseconds milis( 1 );
std::this_thread::sleep_for( milis );
}
AsyncStatus S = A->Status;
}
results in an infinite loop. If called upon other functions it actually works. The problem here is why does a task need to be executed on a particular thread if everything is Async ? Instead of Async it should be RunOn(Main/UI)Thread or similar.
SOLVED, see answer;
This is the magical fix that gets the job done :
Calling
wait
on theconcurrency::task
after you create it completely defeats the point of having tasks in the first place.What you have to realize is that in the Windows Runtime, there are many asynchronous operations that cannot (or should not) be run on (or waited for on) the UI thread; you've found one of them, and now you're trying to wait on it. Instead of potentially causing a deadlock, you're getting an exception.
To remedy this, you need to use a continuation. You're most of the way there; you're already defining a continuation function:
...but you're not using it. The purpose of the function you pass into
then
is to be called off the UI thread once the task is complete. So, instead, you should do this:Your important post-reload code won't run until the task is complete, and it will run on a background thread so it doesn't block or deadlock the UI.
In general you should use the continuations (.then(...)), like Adam's answer says, and not block. But lets say you want to do a wait for some reason (for testing some code?), you can trigger an event from the last continuation (to use C# parlance):
By the way, for some reason this method causes an exception when after it is over in visual studio tests. I've tested it in an app too though and it worked with no problem. I'm not quite sure what the problem is with the test.
If anybody wants a C++/Wrl example then I have that too.
Update 07/08/2017: As requested here is a C++/Wrl example. I have just run this in a Universal Windows (10) Test project in Visual Studio 2017. The key thing here is the weird part
Callback<Implements< RuntimeClassFlags<ClassicCom >, IWorkItemHandler , FtmBase >>
, as opposed to justCallback<IWorkItemHandler>
. When I had the latter, the program jammmed except for when it was in a .exe project. I found this solution here: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/ef6f84f6-ad4d-44f0-a107-3922d56662e6/thread-pool-task-blocking-ui-thread . See "agile objects" for more information.Update 08/08/2017: More example, per the comments.
This outputted:
Just in case anyone needs here is solution in C++/WinRT. Say you have function
ProcessFeedAsync()
that would returnIAsyncAction
, just need following simple code:source