If we make a thread STA like this: Thread.SetApartmentState(STA);
then it cannot run code marked with [MTAThread]
attribute.
We have seen [STAThread]
in windows and console applications but I have never seen code with [MTAThread]
attribute and don't know which .NET libraries use this attribute.
My question is what are the limitations of a thread with apartment state set to STA, in compare to threads with MTA apartment state (natural .NET threads) ?
I don't think it makes any difference if you don't use COM. If you do, then in some instances, COM objects may be only accessible from only one or another type of thread. If the COM object works in both apartments, then try doing performance tests. Or read about COM apartments on MSDN. But I don't think it matters for performance, it's rather a design choice or something.
That's not how it works. The apartment type is a property of a thread, not of a method. You see the [STAThread] attribute applied only to the Main() method of a .NET program. It determines the apartment type of the very first thread that is created to run the program. Necessary because you can't call SetApartmentState() after the thread is running. Beyond that, the attribute has no meaning, the thread stays in an STA for its lifetime. You never see [MTAThread] because that's the default.
A thread that's STA has some limitations. It can never block because that will block and often deadlock any code that tries to call a method of an apartment threaded COM object. And it must pump a message loop so that COM can marshal the method call from another thread. Marshaled method calls can only be executed when a thread is 'idle', not busy executing any code. A message loop provides that 'not busy' state.
There are requirements on the COM component as well. It must support marshaling, either by restricting itself to the subset of types that are supported by Automation so that the standard marshaller can be used. Or by providing a proxy/stub pair for custom marshaling. The
HKCR\Interface\{iid}\ProxyStubClsid32
registry key determines how the marshaling is done.Sharing an apartment threaded object between an STA and an MTA thread is explicitly supported. The STA thread must create it, any calls on the MTA thread (or other STA threads) is marshaled. Which ensures that the component only ever sees calls made on the same thread, thus ensuring thread-safety. No additional locking is required.
Last but not least, if you create an apartment threaded COM object on an MTA thread then COM will automatically create an STA thread to give it a safe home. The only failure mode for this is when the COM component doesn't support marshaling. The one disadvantage of doing it this way is that every call will be marshaled. That's slow.