Creating a non-agile delegate in C++/WinRT, part 3: The other cases and why they aren’t interesting

Raymond Chen

Raymond

We’ve been looking at one specific case of a non-agile delegate, namely a delegate that is invoked on a background thread and wants to execute synchronously on a UI thread. What about the other cases?

Yeah, what about them? Let’s write out a table.

Handled onRaised on
Background threadUI thread
Background threadAlready thereMakes no sense
UI threadresume_synchronousAlready there
Other UI threadresume_synchronous

Two of the boxes are labeled Already there. Those are the cases where the event is raised in the same apartment that you want to handle it, in which case everything is fine and there’s no need to play any apartment-switching games.

Two of the boxes are labeled resume_synchronous. In these cases, you want to run the handler synchronously on a UI thread which is not the one your handler was invoked in. In those cases, you can use the resume_synchronous function we discussed last time. Of course, since you are running on a UI thread, you shouldn’t perform long blocking operations. This is particularly true if you’re in the bottom right corner, because you are holding two UI threads hostage while your event handler is running.

That leaves the last box, labeled Makes no sense.

That box makes no sense.

That box represents the case where the event is raised on a UI thread, but you want to handle it synchronously on a background thread. Why would you do that?

The usual reason for moving to a background thread is to allow you to perform long-running operations without affecting the responsiveness of the UI thread. But that doesn’t help us here, because this table is about running the code synchronously in another apartment, so the UI thread is going to remain unresponsive while the background thread does its work. Switching to the background thread didn’t accomplish anything. You may as well just do it on the UI thread.

Remember that this entire discussion is in the context of running the handler synchronously. If you can run the handler asynchronously, perhaps with the assistance of a deferral, then you should just do that.

We’ll wrap up this discussion next time by connecting this discussion to C++/WinRT in a different way.

 

2 comments

Comments are closed. Login to edit/delete your existing comments

  • Avatar
    Tobias Käs

    > That box makes no sense. […] Why would you do that?

    I actually had to do that for several different reasons in the past:
    – To get out of the UI thread so that COM objects you create aren’t bound to it.
    – To make a cross apartment call and prevent COM message pumping making things reentrant when the caller doesn’t expect it.

    Though luckily getting on a background thread is really easy, so not a problem.

  • Avatar
    Joshua Hudson

    Case: raised on background thread, executes synchronously on other background thread. Why? Thread raising thread is MTA and executing thread is STA. There’s no way to declare MTA->STA temporarily on a thread even though this makes logical sense. (The call we’re inside of isn’t reentrant anyway.) Since the STA thread didn’t have anything else to do, I used a pair of events and a pair of global variables for the handoff.