Use COM STA or MTA Without Shared COM Objects? - c++

This thread is great at explaining STA vs MTA for COM, however it doesn't address how to code for such or when to use one or the other, and only just discusses technicalities about COM apartments being used by thread-safe objects or not. I'd be willing to bet most users just want to know how to use the Win API through COM without any COM objects shared among multiple threads.
Should you use STA always if your COM objects aren't shared among threads, and your code makes use of multiple threads or a single thread each with its own COM object instances, none of the objects shared? Does it depend on the object you are using? If you don't always use STA for such when do you use MTA? Do you ever need a message pump in this case?
In my case I use the Task Scheduler API (ITaskService) and the Shell Links/Create Shortcut API (IShellLink) from the main GUI thread (using the Qt Framework), and the File Operation API (IFileOperation) and the Volume Shadow Copy Service API from a worker thread.
I call CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); from each thread before initializing and using the COM objects and CoUninitialize(); after. Is this proper usage of COM? Would the same apply using COM objects from the main GUI thread without a worker thread?

For making outbound COM calls to objects that you instantiated via CoCreateInstance, STA should be good enough, and is almost a must for your GUI thread (the one that has a GetMessage/DispatchMessage loop).
MTA starts to become relevant when hosting your own thread safe COM objects that are expected to be invoked from other processes.
The documentation for IFileOperation states this:
IFileOperation can only be applied in a single-threaded apartment
(STA) situation. It cannot be used for a multithreaded apartment (MTA)
situation. For MTA, you still must use SHFileOperation.
See all, this link: INFO: Calling Shell Functions and Interfaces from a Multithreaded Apartment
I suspect what the documentation is really trying to say is this:
The class implementing IFileOperation is not thread safe
It's ThreadingModel is declared "apartment" in the registry and will incur marhsalling overhead if accessed from an MTA thread.
On our application, have used ITaskScheduler on the main STA thread. And we use IFileOperation on a background STA thread that has its own message pump.
Some other links that I think are very useful:
https://support.microsoft.com/en-us/help/150777/info-descriptions-and-workings-of-ole-threading-models
https://devblogs.microsoft.com/oldnewthing/?p=22603

Related

When calling EnumThreadWindows - what is the association between non-GUI threads and the enumerated windows?

I am reviewing some code where MTA threads are calling making a call to EnumThreadWindows with their thread ID and looking for a Window with a particular class name. This window is created by an STA COM object explicitly for the purpose of tying an MTA thread to a itself.
I'm sure this works great when there's a single STA object (and therefore only one window); however, in the scenario where there are 8 of these windows and because these are non-GUI MTA threads I am wondering how can these threads be associated with a specific window. We don't create these, they're part of a thread pool in Internet Explorer relating to asynchronous pluggable protocol handling.
Unless I'm missing some 'magic' I would think that the EnumThreadWindows call would result in all windows in the process being enumerated because the threads are non-GUI threads.
I've done some initial exploration of this; however, the scenario in which these operations happen in our code is fairly complicated and doesn't lend it self well to this.
Is the enumeration behavior of EnumThreadWindows explained in more detail than what we see in MSDN?

Why shouldn't gui threads live in multithreaded apartments?

The COINIT - an enumeration used to specify whether a windows thread is in a single or multithreaded apartment - documentation (http://msdn.microsoft.com/en-gb/library/windows/desktop/ms678505(v=vs.85).aspx) states that:
The multi-threaded apartment is intended for use by non-GUI threads. Threads in multi-threaded apartments should not perform UI actions. This is because UI threads require a message pump, and COM does not pump messages for threads in a multi-threaded apartment.
Why shouldn't threads in multi threaded apartments perform UI actions? What is wrong with having a message loop in a thread in a multi threaded apartment? Does COM somehow provide an automatic message loop for a thread in a single threaded apartment?
That's a bit backwards, a UI thread primarily requires a message loop so that it can receive notifications from Windows and other processes. A message loop is the universal solution to the producer-consumer problem. With the operating system and other processes producing, the UI thread consuming.
A UI thread uses lots and lots of code that is not thread-safe. This includes major features implemented in COM, like drag+drop, the clipboard, the shell dialogs, ActiveX controls like a browser. And a raft of code that was never made thread-safe because the programmer didn't have to make it so, much easier to write. Those features require an STA thread, in other words a thread that initializes COM by passing COINIT_APARTMENTTHREADED to CoInitializeEx().
That is a promise to COM that the thread will be a good citizen, it is not allowed to make blocking calls and must pump a message loop. It is the message loop that COM uses to marshal a call from a worker thread to the STA thread in order to keep a COM object thread-safe. When all the calls are made from the same thread then there's never a safety issue. The underlying call is SendMessage(), with a ton of plumbing to copy the function arguments from one stack to another. CoInitializeEx() creates a hidden message window owned by the STA thread that processes the message and actually makes the call. Safely.

STA (Single Threaded Apartment) COM Object - Spawn worker threads?

Is it a bad thing to spawn worker threads in your STA COM object (ie. COM object creates a thread to perform a task)? I think, the answer is - that depends!
For example in my case:
The worker threads that I am using will not interfere/access COM or COM Services.
Reason why I am asking this is because by STA COM definition STA can only house one thread. Spawning multiple threads kind of goes against this principle unless the worker threads and the work they do NOT interfere/deal with COM/COM services.
In this case I am thinking this is perfectly fine and in my opinion the worker threads should not be considered by COM as part of the logical STA.
What are your thoughts on this?
No, that's not a bad thing. Apartments explicitly exist to help you getting multi-threaded code working. An STA thread is a safe home for a COM server that's not thread-safe, COM's apartment threading model ensures that it is always used in a thread-safe way. All you have to do is the marshal the interface pointer you want to use in the worker thread (IGlobalInterfaceTable for example) and you can call the methods without doing anything special.
This doesn't come for free of course, there's overhead involved in marshaling the call. How much depends on how responsive the STA thread is when it pumps its message loop. If you intended to create the worker thread explicitly to use that COM server in a multi-threaded way then of course you'll not be ahead, you made it slower.
Don't let the worker threads use COM in any way, and you should be fine. This means you can't call COM objects in the worker and you can't call COM runtime APIs from the worker... either directly or indirectly.
The important thing to realize is that any new threads you create are new threads in their own right; it actually doesn't matter at all which thread created them. The two things that matter are: (1) that those new threads themselves call CoInitializeEx and either get their own STA each, or share an MTA together, and (2) any COM object pointers you transfer between threads get marshaled appropriately. Do not ever just pass a COM object pointer from one thread to another in a global variable; instead use the GIT or CoMarshalInterThreadInterfaceInStream as appropriate.
(One exception to this: you can pass COM pointers freely between MTA threads; but only once that pointer has been appropriately marshaled into the MTA in the first place.)
Also, you need to be very aware of there objects live and what their affinities are. If you create an object on a STA thread, and marshal a pointer to another thread, then the typical case is that the object will still live on that original STA thread with calls returning to that thread, unless you takes specific steps to specify otherwise. (Things to watch for here: what the object's threading model is, and whether it 'aggregates the free-threaded marshaller'.)
So it's not a bad thing; but be sure that you do it appropriately. For example, you might think that using two threads might be more efficient; but then later on realize that a lot of time is being spent by that worker thread calling back to the object on the original thread, giving you worse performance than a single-threaded case. So you need to think out your threads and object strategy carefully first.
(Having said all of that, you can of course spin up as many threads as you want that don't call CoInitialize, so long as they don't use COM or COM objects in any way; if those threads to need so somehow communicate with the threads that do use COM, it's up to you to manage that communication using any 'classic' IPC mechanism of your choice - eg. messages, globals, etc.)

COM calls from multiple threads

If I call the same COM function from multiple threads to an in proc COM Dll, how thread safe is that?
Do all my objects in the COM DLL also need to be thread safe for this to work reliably?
COM takes care of threading on behalf of the COM server. The server publishes the kind of threading it supports with the ThreadingModel registry key. Very common settings are Apartment or Both. Free is very rare. A missing key is equivalent to Apartment.
COM requires a single-threaded apartment (STA) for apartment threaded servers. If you don't provide one (CoInitialize/Ex call) then it will create a dedicated thread for the server. A hard requirement for an STA thread is that it also pumps a Windows message loop. The message loop is the mechanism by which COM automatically marshals a method call from one thread to another.
So, the general answer to your question is, yes, it normally is thread-safe. There are still things that can go wrong. Deadlock is possible when a call is made from a worker thread but the STA thread isn't pumping. Or the server could be fibbing about the ThreadingModel it registered. Not uncommon with servers implemented in .NET. They get registered as Both, but there are few .NET classes that are actually thread-safe.
See this very detaled article. Basically COM will take care of synchronization - you don't need to bother. However in certain cases the consumer can experience significant slowdown because of synchronization.
Depends upon the COM objects threading model. If its free threaded then you are responsible for thread safety. If its in a single threaded apartment then you can only call it from one, and if it's in a multithreaded apartment, then you can can but as always you have to consider the implications for the object's state. there is a very good answer on SO Could you explain STA and MTA? explaining this.

Asynchronous COM C++ calls

Following up from part of this question, what is the best way to have a worker thread that invokes a COM procedure in a DLL, to do this asynchronously so that the worker thread is not blocked on this call?
Note that a call to this COM DLL can take a long time as it will do DB accesses and possible run long running queries.
I wondered if asynch is possible in this scenario or if one has to just wait for the call to complete?
Take a look at this article:
http://msdn.microsoft.com/en-us/magazine/cc301334.aspx
You can also do it by yourself: create another thread for COM calls, and pass information from your worker thread to it somehow - for instance, using a queue of command pattern objects.
http://en.wikipedia.org/wiki/Command_pattern
This is, in general, not possible. COM takes care of the threading requirements for a COM server. Which it advertises in the registry. Have a look-see with Regedit.exe and locate the HKCR\CLSID{guid} key for the coclass that you use. The ThreadingModel key says what is required.
If it is missing or set to Apartment then the server says that it needs to be created on an STA thread and its interface methods must be called from that same thread. If you call a method from another thread then the call gets marshaled to the STA thread. That's safe but it is slow and you don't have any concurrency.
If it is set to Both then the call is still marshaled when the COM object was created on an STA thread. But not when it was created on an MTA thread. Only Free allows free threading. Which is very rare, the vast majority of COM components are apartment threaded and don't have the internal protection that's required to make calls from a worker thread.
There's typically only one STA thread in a program, the startup thread. It must pump a message loop, a hard requirement for STA. If you don't have one, COM will create an STA thread for you to find a good home for the server. All calls will be marshaled then.
Not good news, I'm sure, there's no free lunch in threading.