locked
how to handle asyn operation when need to return synchrouslly in a winrt method

    Question

  • hi all,

    i am writting a winrt component doing some image processing.

    one of the methods is:

    IVector<int>^  WinRTComponent::ProcessImage(IStorageFile^ input)

    inside this method, i have to copy the file to appdata diretory to enable the use of fopen in a 3rd lib.

    after the copy completed, i will do the real processing and return the result.

    problem is: the copy is asyn and how can i return the result inside the complete handler?

    Tuesday, May 8, 2012 2:59 AM

Answers

  • you can use

    operationstaus   =  status::error (or status::started)

    asyncoperation going

    operationstaus  = asyncoperation->status

    while(operationstaus != status::completed)

    {

         WaitForSingleObjectEx(event_wait,2,false);//wait 2ms

         operationstaus  = asyncoperation->status

               // here you should set wait time out to protect it can't return and blocked

    }



    • Edited by oishixixi Wednesday, May 9, 2012 7:12 AM
    • Marked as answer by adewang82 Wednesday, May 9, 2012 11:08 AM
    Wednesday, May 9, 2012 5:58 AM
  • Ade Wang,

    Can you give me some details about the Exception? Is it a Platform::Exception^? Is the error code something like RPC_E_WRONG_THREAD? The thing is if create_async returns a type T (instead of task<T> or IAsyncOperation<T>), the lambda you call create_async with will execute on a background thread in the MTA. If your entire lambda consists of creating async operations and continuations create async operations as well, you may consider returning the last async operation wrapped in a task - this will ensure that the create_async lambda runs inline. If you give me some pesudocode I may be able to provide better suggestions.

    Note that regardless of whether the create_async lambda returns T, task<T> or IAsyncOperation<T>, the return type of create_async will be IAsyncOperation<T>. In the first case the lambda executes in the background, in the 2nd and 3rd cases, the lambda executes inline (it's assumed here that most of the work is just being created in the create_async lambda and the work itself will execute asynchronously).

    If the error HRESULT is not related to executing on the wrong thread, I'd be curious to know what it is.

    -geni

    • Marked as answer by adewang82 Friday, May 11, 2012 2:11 AM
    Thursday, May 10, 2012 11:00 PM

All replies

  • you can use

    operationstaus   =  status::error (or status::started)

    asyncoperation going

    operationstaus  = asyncoperation->status

    while(operationstaus != status::completed)

    {

         WaitForSingleObjectEx(event_wait,2,false);//wait 2ms

         operationstaus  = asyncoperation->status

               // here you should set wait time out to protect it can't return and blocked

    }



    • Edited by oishixixi Wednesday, May 9, 2012 7:12 AM
    • Marked as answer by adewang82 Wednesday, May 9, 2012 11:08 AM
    Wednesday, May 9, 2012 5:58 AM
  • Hello,

     

    I think you can do all of these in  the asynchrouslly way. You can follow this sample to open file and copy the file data using Windows.Storage.Streams namespace

    http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597#content

    You can write the code in .then() function when the copy operator completed.

     

    Best regards,

    Jesse


    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, May 9, 2012 6:48 AM
  • Hi, oishixixi

     your solution is good.  i just spend several hours to figure out how to do this.

     firstly, i used below code to perform an asyncoperation  synchronously.

    template <typename TResult>
    TResult PerformSynchronously(Windows::Foundation::IAsyncOperation<TResult>^ asyncOp)
    {
    	Concurrency::event synchronizer;
     	Concurrency::task<TResult>(asyncOp).then([&](TResult taskResult) {
    		synchronizer.set();
    	}, Concurrency::task_continuation_context::use_arbitrary() );
    	synchronizer.wait();
    	return asyncOp->GetResults();
    }

    but a strange thing is that  when i set a breakpoint in synchronizer.set(), the function works as expected.

    but if there is no breakpoint,  synchronizer.set() is not called most of the time and the app is just stuck at synchronizer.wait();

    finally, i have had to modify the function as below:

    template <typename TResult>
    TResult PerformSynchronously(Windows::Foundation::IAsyncOperation<TResult>^ asyncOp)
    {
    Concurrency::event synchronizer;
      while( 0 != synchronizer.wait(10))
    {
    if(asyncOp->Status == Completed)
    return asyncOp->GetResults();
    }
    return asyncOp->GetResults();
    }




    • Edited by adewang82 Thursday, May 10, 2012 10:41 AM
    Wednesday, May 9, 2012 11:23 AM
  • Ade Wang,

    I have a quick question about the use of your API. Can your API be called on the UI thread? If so, is it not a concern for you that the UI thread could be blocked and unable to be responsive while your function is executing? Is there not a way by which your api can be consumed asynchronously. With tasks, you can compose multiple async operations together and return a task from the function that someone can schedule a continuation to.

    I understand it can be annoying to have to change all your call sites from using sync to async, but a bit of refactoring now can go a long way in making your app more responsive.

    --Geni

    Wednesday, May 9, 2012 9:15 PM
  • Hi Geni,

    Yes, you are right, the UI thread are blocked when this api is executing.

    i have tried to implement the API to be async, but failed due to another question.

    IAsycOperation<IVector<int>^>^  WinRTComponent::ProcessImage(IStorageFile^ file)

    {

    m_file = file;

    return create_async([this] -> IVector<int>^{

       IAsyncOperation<IStorageFile^>^ op = m_file->CopyAsync(....)..   //// this line will thow an exception when running

    });

    }

    do you have any idea how to resolve this? or am i using create_async in a wrong way?

    Thursday, May 10, 2012 12:19 AM
  • Ade Wang,

    Can you give me some details about the Exception? Is it a Platform::Exception^? Is the error code something like RPC_E_WRONG_THREAD? The thing is if create_async returns a type T (instead of task<T> or IAsyncOperation<T>), the lambda you call create_async with will execute on a background thread in the MTA. If your entire lambda consists of creating async operations and continuations create async operations as well, you may consider returning the last async operation wrapped in a task - this will ensure that the create_async lambda runs inline. If you give me some pesudocode I may be able to provide better suggestions.

    Note that regardless of whether the create_async lambda returns T, task<T> or IAsyncOperation<T>, the return type of create_async will be IAsyncOperation<T>. In the first case the lambda executes in the background, in the 2nd and 3rd cases, the lambda executes inline (it's assumed here that most of the work is just being created in the create_async lambda and the work itself will execute asynchronously).

    If the error HRESULT is not related to executing on the wrong thread, I'd be curious to know what it is.

    -geni

    • Marked as answer by adewang82 Friday, May 11, 2012 2:11 AM
    Thursday, May 10, 2012 11:00 PM
  • hi geni,

    the error code is RPC_E_WRONG_THREAD.

    I have wrapped the last async operation in task. the app runs well now.

    A question:

    IAsyncOperation can only be used in a STA?

    Friday, May 11, 2012 2:11 AM
  • From what I know about the file operations in the Consumer Preview version, if a file related operation is created on an STA thread it is usually bound to that STA thread - also if you got a completion callback /task continuation on the STA thread and the file object was retrieved inside that continuation, it also cannot be used on a background thread without a proxy. I am not certain whether this behavior will change in the future.

    Monday, May 14, 2012 5:28 PM