Is possible having two COM STA instances of the same component? - c#

I had a problem discovered on another thread here, I need to access a COM component that is STA. I'll run it on a dual-core computer, a process using this component only reaches 50% of CPU. Unfortunately, the owners said they can't change the component to MTA, because the component is a hybrid system compiled at Matlab, which core is C.
So I tried to load two instances of the COM class on the same process, different threads accessing it, but I couldn't, only the last COM instance becomes usable. Do you know anything that could solve this problem?
I am considering running two processes of my service on the same computer, to achieve 100% cpu. This is not a good solution, mainly because this servers will be installed outside our infra.

On the topic of multiple STA components
It is possible to have two instances of the same STA COM component and access them from C#. The only thing that could prevent you from such scenario is the object itself if implemented as a singleton object.
However, if both instances are on the same STA thread, an active call in one of the instances will block any other calls into that thread. Thus, if you want those two instances to work in parallel, you need to have them be on separate STA threads. Just to be on the safe side, I'd create both instances on background threads. That should prevent your UI from locking.
On the topic of STA vs. MTA for the external component
I am not sure why the component being in C would prevent it from being an MTA object. Being MTA just means the object needs to internally synchronize it's state access and management code between multiple threads.
WARNING: Ugly hack! :-) If you want to experiment a bit, you could go to the registry and change the external component threading model from Apartment to Free, just to verify that your code would work properly with an MTA. Their component will probably break, though, as they probably did not write thread-safe code, relying on COM to guard them.
Make a note on a prominent place to revert that change later, so that you don't end up with a system where their code doesn't work and spent countless hours chasing ghosts. :-)

Franci Pernov,
I've tried work with two threads, and initialize the com instances on the context of each thread, but the error is the same: (Exception from HRESULT: 0x80004005 (E_FAIL))
I am storing and retrieving the instance through CallContext GetData and SetData.

Try registering a second class using the same DLL. Consider that you may actually need a separate copy of the DLL with a different name in order to be completely safe.
Just remember that the STA COM class (and perhaps its DLL) is not considered thread safe for multi-threading and there is nothing you can do about that external to the COM class.

Related

C#.NET: "Multi Threaded Apartment" and "Multithreading"

I am learning multi threading concepts (in general and targeted to C#.NET). Reading different articles, still could not fully understand few basic concepts.
I post this question. "Hans Passant" explained it well but I was not able to understand some of its part. So I started googling.
I read this question which have no answers.
Is Multithreading and MTA same?
Suppose I write a WinForm application which is STA (as mentioned above its Main() method), still I can create multiple threads in my application. I can safely say my application is "multi-threaded". Does that also mean my application is MTA?
While talking about STA/MTA, most of the articles (like this) talk about COM/DCOM/Automation/ActiveX. Does that mean DotNet have nothing to do with STA/MTA?
No. MTA is a property of a single thread, just like STA. You now make the exact opposite promise, you declare that the thread does absolutely nothing to keep external code thread-safe. So no need to have a dispatcher and you can block as much and as long as you like.
This has consequences of course and they can be quite unpleasant. It is deadly if the UI thread of your program is in the MTA since it uses so many external components that are fundamentally thread-unsafe. The clipboard won't work, drag+drop doesn't work, OpenFileDialog typically just hangs your program, WebBrowser won't fire its events.
Some components check for this and raise an exception but this check isn't consistently implemented. WPF is notable, while apartment state normally matters only to unmanaged code, WPF borrowed the concept and raises "The calling thread must be STA, because many UI components require this." Which is a bit misleading, what it really means is that the thread must have a dispatcher to allow its controls to work. But otherwise consistent with the STA promise.
It can work when the component uses COM and the author has provided a proxy. The COM infrastructure now steps in to make the component thread-safe, it creates a new thread that is STA to give it a safe home. And every method call is automatically marshaled so it runs on that thread, thus providing thread-safety. The exact equivalent of Dispatcher.Invoke() but done entirely automatic. The consequence however is that this is slow, a simple property access that normally takes a few nanoseconds can now take multiple microseconds.
You'd be lucky if the component supports MTA as well as STA. This is not common, only somebody like Microsoft goes the extra thousand miles to keep their libraries thread-safe.
I should perhaps emphasize that the concepts of apartments is entirely missing in the .NET Framework. Other than the basics of stating the apartment type, necessary since .NET programs often need to interop with unmanaged code. So writing a Winforms app with worker threads is just fine, and those worker threads are always in the MTA, you do however get to deal with thread-safety yourself and nothing is automatic.
This is generally well-understood, just about everybody knows how to use the lock keyword, the Task and BackgroundWorker classes and knows that the Control.Begin/Invoke() method is required to update UI from a worker thread. With an InvalidOperationException to remind you when you get it wrong. Leaving it up to the programmer instead of the system taking care of thread-safety does make it harder to use threads. But gives you lots of opportunities to do it better than the system can. Which was necessary, this system-provided thread-safety got a serious black eye when Java punched it in the face during the middleware wars of the late 90s.
There are some questions but first let's start by this:
An Apartment is a context where a COM object is initialized and executed, and it can be a either single thread (STA), normally used for not thread-safe objects, or multi thread.
the term apartment, which describes the constructs in which COM
objects are created
From: https://msdn.microsoft.com/en-us/library/ms809971.aspx
So Multithreading and MTA are not the same, but MTA is Multithreaded.
We can say that STA and MTA are related to COM objects.
You can read more here: https://msdn.microsoft.com/en-us/library/ms693344(v=vs.85).aspx
So, for your second question, if your WinForm application is "multi-threaded" does not mean it is "MTA".
Finally, the MTA/STA concepts are older than .Net technology, but we cannot say that they have nothing related to, because .Net supports COM technology in both STA and MTA.
I expect my answer help you to undestand the difference between Apartment and Threading.
More interesting reading here:Could you explain STA and MTA?

Switching between STAThread and MTAThread and memory leaks

While looking for a memoryleak in a vb.net WebService, I detected that finalizers where blocked, and so several objects where never released (e.g. System.Threading.ReaderWriterLock)
Google told me that this might be, because the STAThread Attribute is set on my main method.
It took a long while until I found out that VB.net uses STA-as default, while c# uses MTA.
When I added the MTAThread-Attribute to my Main Method, everything worked fine and objects are released.
So if I understand it right, the Finalizer-Thread is blocked in STA-Mode.
So far so good, but to be honest, I heard about STA and MTA today for the first time.
Can I switch between STA and MTA without any thoughts?
UPDATE
I'm still not sure if I can switch between MTA and STA without breaking my code.
Here are some more thoughts
I do not use COM Objects in my code.
But some other libraries I'm using seem to use them under the hood, for example OracleCommand
My application is written in vb.net, and so by chance it is set to STA-Appartment, since this is the vb.net default, which I did not know at development time
If I wrote my application in c#, it would be set to MTA by default
So do I need to care about the COM Objects that are used under the hood or not?
because the STAThread Attribute is set on my main method
Yes, that's a regrettable practice that VB.NET inherited from VB6. A strong goal in COM (the original underpinning of VB6 and what you use in your web service) was to hide the complexities of threading and dealing with thread-unsafe code automatically without the client programmer having to know anything about it. A COM object tells the COM runtime what kind of threading it supports. By far the most common choice is "Apartment", a confuzzling word that means that it is not thread-safe.
COM solves thread-safety issues by automatically marshaling a call of the COM method from a worker thread to the thread on which the COM object was created. Thus guaranteeing thread-safety for the COM object. The equivalent in .NET is Dispatcher.Invoke() or Control.Invoke(). Methods that you have to call explicitly in a .NET program to keep the thread-unsafe user interface working, it is done entirely automagically for a COM object.
That kind of marshaling is pretty expensive, it inevitably involves two thread context switches plus the overhead of serializing the method arguments, tens of thousands of CPU cycles at a minimum.
A thread can tell COM that it is a friendly home for a thread-unsafe COM object and will take care of the marshaling requirements, it marks itself as a Single Threaded Apartment. STA. Any calls it makes to a COM method do not have to be marshaled and run at full speed. If a call is made from a worker thread then the STA thread takes care of actually making the call.
An STA thread however has to abide by two very important rules. Breaking one of those rules causes very hard to diagnose runtime failure. Deadlock will occur if you break those rule, like you observed for your finalizer thread. They are:
An STA thread must pump a message loop. The equivalent of Application.Run() in a .NET program. It is the message loop that implements the universal solution to the producer-consumer problem. Required to be able to marshal a call from one thread to a specific other thread. If it doesn't pump then the call made on a worker thread cannot complete and will deadlock.
An STA thread is not allowed to block. Blocking greatly increases the odds for deadlock, a blocked thread isn't pumping messages. The lesser problem in a .NET program, the CLR has a great deal of support for pumping itself on calls like WaitHandle.WaitOne() and Thread.Join().
Sometimes the COM component itself will make hard assumptions about being owned by an STA thread. And use PostMessage() internally, usually to raise events. So even though you never actually make any calls on a worker thread, the component will still malfunction. WebBrowser is the most notorious example of that, its DocumentCompleted event won't fire when the thread doesn't pump.
Your web service no doubt violated the first bullet. You only get a message loop automatically in a Winforms or WPF application. And yes, poison to the finalizer thread since its final release call on the COM object must be marshaled to keep the object thread-safe. Deadlock is the inevitable outcome since the STA thread isn't pumping. A ratty problem that's pretty hard to diagnose, the only hint you get is that the program's memory usage explodes.
By marking the thread as MTA, you explicitly promise to not provide a safe home for an apartment-threaded COM server. COM is now forced to deal with the hard case, it must create a thread by itself to provide safety. That thread always pumps. While that can solve the problem with your web server, it should be noted that this is not a panacea. Those extra threads do not come for free and the calls are always marshaled so always slow. Getting too many of those helper threads is a ratty problem that's pretty hard to diagnose, the only hint you get is that the program's memory usage explodes :)
Automatic thread-safety is a very nice feature. It works 99% of the time without any hassles. Getting rid of the 1% failure mode is however a very major headache. Ultimately it boils down to the universal truth, threading is complicated and error prone. One approach is to not leave it up to COM but take the threading bull by the horns yourself. The code in this post could be helpful with that.

simple example of thread crossing application domains?

I've been reading up a bit on Application Domains and Threading, and I came across this statement:
"A particular thread is not confined to a single application domain. That is, threads are free to cross application domain boundaries; a new thread is not created for each application domain."
Now that's all well and good, but I thought to myself - when exactly is that crossing of domains by the thread going to happen?
I have seen examples of people creating Application Domains and using CreateInstanceAndUnwrap and MarshalByRefObject. But - marshalling is available between completely seperate processes! So meh - that's not what I call "free to cross".
Can anyone provide example (C#) code of a thread crossing application domains without marshalling, as I do not consider this "free"? (or am I just totally muddled up as usual).
Well, simple, CreateInstanceAndUnwrap() makes the thread cross the AppDomain barrier. After all, the created object exists in the AD, the thread must make the transition in order to call the constructor. Additional crossing happen when you then make calls through the proxy to call the class methods.
And AppDomain is not a barrier for code, it isolates data. Each AD has its own GC and loader heap. Serialization is required to cross that data barrier. But it is the exact same thread to deserializes again and continues execution. Which is quite distinct from marshaling between processes, that has to happen between two distinct threads. With the considerable overhead of marshaling between distinct virtual memory views and the required thread context switch. An AD is a much cheaper version of a process.
I do not believe a user thread can cut across multiple appDomains. However, CLR worker threads, GC threads and the like will and can do.
One example could be calling native code and the native code calls a callback in another appdomain.
And marshaling inside a process might use an optimized route where the same OS thread is used in multiple AppDomains.

Using legacy COM component in C# multithreaded Environment

I have legacy COM component, and my mission is to write web service that wrap the COM and enable concurrent non-blocking calls.
First of all, because the COM object itself is stateless, i decided to use the [ThreadStatic] attribute so each thread will have its own instance of the COM object to prevent the use of lock { } statement and enable real concurrent processing, but it seems that all calls still procceeded synchronous.
I wrote a test code that runs a method from the COM component synchronous with for { } loop, and then added second thread that doing exactly the same but to another instance of the COM object, and i saw no changes, X calls always consume Y timespan, no matter of threads count. Its like there is a static lock or something...
In spite of that, separate processes can process each one call concurrently for real. What prevent from separate threads to behave the same?
What can i do to enable real concurrent calls to the COM component?
COM is threading aware and will honor the threading model requested by the coclass. It publishes its threading requirements with the ThreadingModel value in the registry. If it is set to "Apartment" (or is missing), COM will make sure all method calls are made from a single threaded apartment by returning a proxy for the interfaces you QI. The proxy ensures the call is marshaled to the correct thread.
You could cheat and use the interface pointer that you got when you created the coclass in an STA thread and make calls without marshaling. Given that the coclass already said it isn't capable of multi-threading, this is very unlikely to work correctly. You'll just randomly corrupt internal state.

Call VB6 DLL from a multithreaded c# windows service application?

I'm running a multithreaded windows service that need to call a VB6 dll. There's no documentation about this VB6 dll and this legacy system supports a very critical business process.
At first time (1st thread), this dll performs well. As other threads need access, it start provide wrong results.
I read one guys saying:
"Just be careful of one thing if you are using VB6. Your threading
model is going to have to change to support apartments if you are
running a multithreaded service. VB only supports multiple
single-threaded apartments, but .NET runs fully free threaded
normally. The thread that calls into the VB6 DLL needs to be
compatible with the DLL."
Another guy from team gave me the idea to put this ddl in a separated application domain. But I'm not sure.
How can we work with VB6 dll called from a multithreaded c# windows service application?
When the threads come in, are you saving objects and reusing them later on new threads? If you can, create the objects fresh for every thread. We have a situation like this with a data layer dll we use. If you create a connection on one thread, it can't be used from another. If you create a new connection on each thread, it works fine.
If it's slow to create your objects, look at the ThreadPool class and the ThreadStatic attribute. Threadpools recycle the same set of threads over and over to do work, and ThreadStatic lets you create an object that exists for one thread only. eg
[ThreadStatic]
public static LegacyComObject myObject;
As a request comes in, turn it into a job and queue it in your thread pool. When the job starts, check if the static object is initialised;
void DoWork()
{
if (myObject == null)
{
// slow intialisation process
myObject = New ...
}
// now do the work against myObject
myObject.DoGreatStuff();
}
You say
I'm running a multithreaded windows
service that need to call a VB6 dll.
There's no documentation about this
VB6 dll and this legacy system
supports a very critical business
process.
and at the same time you say
At first time (1ยบ thread), this dll
performs well. As other threads need
access, it start provide wrong
results.
I'd make very certain that Management is aware of the failure you're seeing because the code supporting the critical business process is old and undocumented, and is being used in a way it was never intended to be used, and was never tested to be used. I bet it's also never been tested to be used from .NET before, has it?
Here's my suggestion, and this is similar to something I've actually implemented:
The VB6 DLL expects to be called on a single thread. Do not disappoint it! When your service starts, have it start up a thread of the appropriate type (I can't say, since I've deliberately forgotten all that STA/MTA stuff). Queue up requests to that thread for access to the VB6 DLL. Have all such access go through the single thread.
That way, as far as the VB6 DLL is concerned, it's running exactly as it was tested to run.
BTW, this is slightly different from what I've implemented. I had a web service, not a Windows Service. I had a C DLL, not VB6, and it wasn't COM. I just refactored all access to the thing into a single class, then put lock statements around each of the public methods.
This article on multithreading Visual Basic 6 DLL's provides some insight. It says:
To make an ActiveX DLL project
multithreaded, select the desired
threading options on the General tab
of the Project Properties dialog box.
This article says there are three possible models to choose from:
One thread of execution
Thread pool with round-robin thread assignment
Every externally created object is on its own thread
I assume that the default is one thread of execution, and that one of the other two options needs to be selected.
You might want to take a look at this: linky
And here is a snippet that caught my attention:
VB6 COM objects are STA objects, that means they must run on an STA thread.
You did create two instances of the object from two MTA threads, but the object itself will run on a single (COM (OLE) created) STA
thread, and access from the two MTA threads will be marshaled and synchronized.
So what you should do is, initialize the threads as STA so that each objects runs on his own STA thread without marshaling and you
will be fine.
Anyway, VB style COM objects are always STA. Now in order to prevent apartment marshaling and thread switching you need to create
instances in STA initialized apartments.
Note also that when you set the [MTAThread] attribute on Main, you effectively initialize the main thread as MTA, when you create
instances of STA objects from MTA threads COM will create a separate (unmanaged) thread and initialize it as STA (this is called the
default STA), all calls to STA objects from MTA threads will be marshaled (and incur thread switches), in some cases Idispatch calls
will fail due to IP marshaling failures.
So the advise is use STA (and therefore VB6) objects from compatible apartments only.

Categories

Resources