locked
WIC object created in Background tasks and accessed in main UI thread

    Question

  • Hi,

    i have some doubts regarding some fundamental aspects involving Asychronous programming  , UI thread and thread apartment.

    before i dive into my questions, i want to list my understanding of Threading/Apartment 

    1. the main UI thread of WSP (windows store apps ) runs in ASTA ( application single threaded apartment )

    2. All background asynchronous tasks ( like say, the one created by create_task construct ) runs in a thread which is from a MTA apartment. (assuming the task and its continuation block ( "then" ) context is set to "arbitrary" context ) 

    3. Objects created in one apartment can only be accessed by threads of that apartment. if the thread from different apartment has to access an object then it will be marshaled. 

    i have following questions to which i dont have concrete answers yet ...

    are my above stated 3 assumptions correct ? 

    i need more clarity on point 3. 

    lets say, i create a WIC bitmap source object in a background task from a given image file. now, this object will become part of the MTA apartment .. right ? 

    now, when i try to access this object from main UI Thread, the calls to this object should be marshelled right ? 

    the reason i am asking is .. i have the above scenario in my sample app and the calls to the bitmap source object in the UI thread are direct and it is not marshelled at all ... looks like there is something wrong in my understanding of the underlying working of threading/apartment and accessing COM objects. 

    shouldnt the calls by marshelled ? 

    Thanks,


    Raj

    Wednesday, November 27, 2013 7:03 PM

Answers

  • Hi CCRaj,

    I have told you why in 2#:

    And when you want to update UI, you need to declare the operation as concurrency::task_continuation_context::use_currentwhich will force the task execute follow the thread that called task::then .

    When you declare  your task chain as above, the task will follow the context of the thread who called task::then(the thread who creates the task).

    In your sample, you create the task in UI thread, so you could use UI element in the task after you declare concurrency::task_continuation_context::use_current.

    If you create a new task from a task(not UI thread), you will detect that what ever you do, you couldn't use UI element ever.

    So please trust me, because what I have said is right. :)

    Regards!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, December 03, 2013 2:36 AM
    Moderator

All replies

  • Hi CCRaj,

    Welcome here!

    In an app that has a UI, the ASTA (Application STA) thread is responsible for pumping window messages and is the only thread in the process that can update the STA-hosted UI controls. This has two consequences. First, to enable the app to remain responsive, all CPU-intensive and I/O operations should not be run on the ASTA thread. Second, results that come from background threads must be marshaled back to the ASTA to update the UI. In a C++ Windows Store app, MainPage and other XAML pages all run on the ATSA. Therefore, task continuations that are declared on the ASTA are run there by default so you can update controls directly in the continuation body. However, if you nest a task in another task, any continuations on that nested task run in the MTA. Therefore, you need to consider whether to explicitly specify on what context these continuations run.

    intensive and I/O operations, you need to declare the operation as  concurrency::task_continuation_context::use_arbitrary which will force the task execute background.

    And when you want to update UI, you need to declare the operation as concurrency::task_continuation_context::use_currentwhich will force the task execute follow the thread that called task::then .

    So, if you build your project along with above, it needn't to be marshaled.

    I hope it is helpful!

    Regards! 


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, November 28, 2013 2:03 PM
    Moderator
  • Thanks for reply, sorry to say that it doesnt answer the specific questions i asked. 

    i kind of pretty much already understand the things you have mentioned above .. 

    my questions was this - 

    lets say i create a WIC BitmapSource object ( IWICBitmapSource ) in a background task ( which is run in a MTA ) 

    and return this object to the main UI thread (say, in a task-continuation ) and i try to access the functions of this object from the UI main thread. 

    what happens in this case ? are the calls marshelled ? 

    because COM object created in a an MTA apartment , only the thread belonging to that aparmtment can access it directly. so , only the background tasks ( which are threads running in a MTA ) can access it, and if this object is  accessed from the UI Main thread, which is an ASTA , then the calls should be marshelled.

    but as mentioned in my first post , that doesnt seem to be case , calls are happening directly.

    i wanted to understand the underlying mechnism in the above case, i might be missing something here.

    Regards,


    Raj

    Thursday, November 28, 2013 6:34 PM
  • Hi CCRaj,

    Welcome back!

    Have you tried Dispatcher?

    You can find an example of the C++ syntax to get back to the UI thread in the ApplicationData Sample. See the HighPriority.xaml.cpp

     // This event handler may be invoked on another thread, so use the Dispatcher to invoke the UI-related code on the UI thread.
        auto callback = ref new DispatchedHandler(
            [this]() { DisplayOutput(true); },
            CallbackContext::Any
            );
        this->Dispatcher->RunAsync(CoreDispatcherPriority::Normal, callback);

    Regards!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.



    Friday, November 29, 2013 2:27 AM
    Moderator
  • i guess we are out of sync with each other ... 

    i am *not* asking about *how to run a piece of code in UI thread*

    i am asking about *what happens* when i try to access the bitmapsource object ( that is created in an background task) in UI Thread.

    Please re-read my question and response ..

    Regards, 


    Raj


    • Edited by naiveCoder Friday, November 29, 2013 7:07 AM
    Friday, November 29, 2013 7:06 AM
  • Hi CCRaj,

    I have read your question carefully, and you should marshal your data to update UI thread from a background task not the UI thread access the data directly.

    Then, what is "marshal"? How could you do it in Windows store app?

    One of the answers is DispatchHandler. It is used to give you a choice to marshal the data to UI thread after the background task completes, it doesn't make sence UI thread without any notification to access data from background task.

    And note it, no any mechanism will help you to do "marshal" if you do nothing but access background task directly, nothing will happen.

    Within your point3:

     Objects created in one apartment can only be accessed by threads of that apartment. if the thread from different apartment has to access an object then it will be marshaled.

    "it will be marshaled", not "system or compiler to do ", but "you to do".

    The method I have shared with you above. :)

    I hope it is helpful!

    Regards!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Friday, November 29, 2013 7:55 AM
    Moderator
  • Thanks for the reply.
    sorry, i am still not convinced :)

    i will try to give a code reference 

    lets say i have button in the xaml and in the button click handler i am doing the following 

    void ButtonClickHander(Object^ sender , RoutedEventsArgs^ args)
    {
         auto createPixelsTask = create_task([]()
         {
          // We are in a background task now 
             IWICBitmap*pIBitmap = NULL;
             //create a bitmap object by some means - like the way it is mentioned in
              //http://msdn.microsoft.com/en-us/library/windows/desktop/ee719661(v=vs.85).aspx
              //here IWICBitmap will be created - this happens in background thread and hence runs in MTA apartment. 
             //and so the IWICBitmap can be accessed by only threads belonging to this apartment.
               //i am returing this object to the task continuation which will run in a UI Thread.
            return ipBitmap;
         }).then( [](IWICBitmap *pIBitmap){
              //this is main UI Thread
              //now, i am trying to access some methods of the given object
              UINT width , height;
              pIBitmap->GetSize(&width , &height);
               //the above function is returning correct values - 
         
          //NOW , my basis of the question was - how come the above call is succedding ? shouldnt this thrown an exception that 
    // object is accessed from a different Aparment ? 
          } , task_continuation_context::use_current() )
    }

    Thanks,

    Raj

    Monday, December 02, 2013 6:26 PM
  • Hi CCRaj,

    I have told you why in 2#:

    And when you want to update UI, you need to declare the operation as concurrency::task_continuation_context::use_currentwhich will force the task execute follow the thread that called task::then .

    When you declare  your task chain as above, the task will follow the context of the thread who called task::then(the thread who creates the task).

    In your sample, you create the task in UI thread, so you could use UI element in the task after you declare concurrency::task_continuation_context::use_current.

    If you create a new task from a task(not UI thread), you will detect that what ever you do, you couldn't use UI element ever.

    So please trust me, because what I have said is right. :)

    Regards!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, December 03, 2013 2:36 AM
    Moderator