Search code examples
c++-winrtwinrt-async

WinRT/C++ What is apartment_context actually?


What I know is that apartment_context is used to capture UI Thread and return to the UI Thread when it is in the background ThreadPool.

So, what is apartment_context actually in WinRT/C++? And how to use it properly and correctly? Then, is this object only able to capture UI Thread?

Finally, what are the advantages and disadvantages of using apartment_context compared to resume_foreground() and CoreDispatcher::RunAsync()?

Thanks


Solution

  • A winrt::apartment_context

    captures the thread context within a coroutine so that it can be restored later. You instantiate a winrt::apartment_context value, and then later you co_await it.

    In other words, it allows client code to store information about the current thread's apartment, switch to another apartment, and later return to it. It can be constructed on any thread, not just UI threads. However, since UI threads live in the special1 ASTA (Application Single-Threaded Apartment) and objects owned by those threads frequently have thread-affinity, apartment_context is primarily used with UI threads.

    The implementation wraps an IContextCallback interface captured from a call to CoGetObjectContext. Its ContextCallback method

    enters the object context, executes the specified function, and returns.

    This is fairly advanced with little to no official documentation available. Luckily, Raymond Chen has published two blog entries2,3 that cover this area in sufficient detail.

    The interface of apartment_context, by contrast, doesn't expose any of that complexity. It consists of a default constructor, and the three members await_ready(), await_suspend(), and await_resume() that make it a coroutine awaiter4. Consequently, the only operations client code performs is to construct, and co_await it. Examples and explanations can be found at Programming with thread affinity in mind.

    As for advantages and disadvantages, it comes down to understanding what's going on. While apartment_context works as advertised, it's important to keep in mind, that it captures the current context. As such, whether a coroutine works as desired becomes a liability of the caller. If (part of) a coroutine needs to execute on the UI thread, it's more robust to use resume_foreground, and more readable, too. The only downside here is that you need access to a dispatcher.

    Finally, CoreDispatcher::RunAsync ultimately does the same thing. Except, it's part of the Windows Runtime, whereas resume_foreground() is part of the C++/WinRT library. I'm not aware of any functional differences.


    1 What is so special about the Application STA?

    2 How do you get into a context via IContext­Callback::Context­allback?

    3 Using contexts to return to a COM apartment later

    4 C++ Coroutines: Understanding operator co_await