I am working on a COM API written in C++ with ATL, which clients will be expected to use in C# via it's COM interop facilities. Currently all the COM objects are only written to support the single threaded apartment model.
Some of the functions of this API cause a separate worker thread to be spawned, which listens for events from a server. In response to events from the server this worker thread creates some fairly simple COM objects, and then passes these objects to a COM event. There are other functions on the API which cause the API to stop listening for events from the server, and then shutdown the worker threads.
As I understand it, the rules of STA are that code for an STA COM object will only ever be run on the thread on which it's created. Unfortunately this seems to be causing disconnected context warnings because the .NET COM interop is caching references to all the COM objects that have been created on this thread, and the thread is shutting down before these references are released.
I can see a few potential solutions to this problem:
- I could modify our COM objects to support the MTA threading model, so the destruction of their creating thread is no longer a problem. This could be a fairly time-consuming task however, and could open me up to other threading related problems.
- I could add some reference counting to keep the worker thread alive until all of it's COM objects have definitely been released. This seems like it might be an error prone approach.
- I could add a whole new thread that is designed to run forever (or at least till the app ends) that deals with the creation of COM objects and the firing of events. Having a single thread for this purpose would likely create a bit of a performance bottleneck though, which I'm not too keen on.
All of the approaches above seem to have their drawbacks, so I was wondering if anyone with experience of dealing with these sort of issues had any other approaches to offer? Or if there are any advantages or drawbacks I haven't mentioned for the above approaches?
I ended up going for option 1 in the original question and switching each of the COM objects over to run in MTA threading model. All of the COM objects were just read-only wrappers around some data so they were already mostly thread safe and switching to MTA was just a case of updating a few .rgs files and some CoInitializeEx calls.
Maybe not the perfect solution for everyone, but hopefully this helps anyone who runs into this problem in the future.