Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

COM multi-threading support

Working with COM for the first time I have got this COM dll, say ABCServer.dll, i created a RCW and added reference to it in my project. Now my application creates several threads and each thread creates certain classes from COM dll and works with them. But then each thread is waiting while other thread is working with certain class from COM dll.

The whole purpose of modifying my application was enabling multi-threading on it. Now when multithreading is happening at my side, the COM causing it to be sequential. Although each thread is creating new instances, why are they waiting for others to be processed?

like image 235
EagerToLearn Avatar asked Oct 28 '11 14:10

EagerToLearn


2 Answers

If your COM component is marked as STA (single-threaded apartment) then there's nothing you can do to make it multi-threaded; the requirement of the component is that all calls to it are serialized onto the thread that the STA is on, and COM handles that automatically for you.

That said, if your component is an STA component (and it seems like it is) and you can't change it to be a multi-threaded apartment component (MTA) or even better, free-threaded (so there is no marshaling between apartments at all) because a) it was written in VB6, or b) it's a third-party dll, then you might be better off working with some sort of queue model.

Basically, have all of your other work run asynchronously, then have a thread (or process, it's up to you), that will consume requests to call this component one at a time, as fast as it can (mind you, you can instantiate multiple instances of this component in multiple threads, you just have to make sure you set the ApartmentState property on the Thread class to ApartmentState.STA) and then publish events/callbacks when the call is complete and continue your other work asynchronously.

It's basically like having two producer/consumer implementations, one to dispatch the calls to the COM component, and another to dispatch the results when done.

like image 102
casperOne Avatar answered Sep 30 '22 14:09

casperOne


There's considerable confusion in the comments and answers posted so far. STA or MTA is a property of a thread. But what matters is what the COM component requires. That's declared in the ThreadingModel registry value. You found "Apartment", a very common setting. It means that the component does not support threading.

This is not unlike the vast majority of classes in the .NET framework, there are very few that are thread-safe. The big difference is that COM enforces threading safety. With .NET classes it is up to you to write your code so the class objects are used in a thread-safe manner. That's difficult to get right and a chronic source of very hard to diagnose bugs but well designed locking allows you to sail around the restrictions. That's not possible with COM, it will always provide thread-safety without you helping. Even if you do want to help.

The only way to get ahead is to create and use the COM component from only one thread. That thread must be initialized with Thread.SetApartmentState() to select STA. Which prevents COM from creating its own thread to find a safe haven for the component. And you must pump a message loop, an STA requirement. Which can be painful and might be avoided if you don't try to use the COM component from another thread and the component itself doesn't depend on having a message pump available. Which is pretty common btw. You'll notice it needs one when it stops being responsive, typically not firing an event when expected. Only make calls on the COM object from the same thread to get concurrency with other threads that create their own object. This is not typically useful or possible.

like image 24
Hans Passant Avatar answered Sep 30 '22 16:09

Hans Passant