April 8th, 2020

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

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 on Raised on
Background thread UI thread
Background thread Already there Makes no sense
UI thread resume_synchronous Already there
Other UI thread resume_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.

 

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • 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.

  • 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...

    Read more