Although there are many questions about COM and STA/MTA (e.g. here), most of them talk about applications which have a UI. I, however, have the following setup:
A console application, which is by default Multi-Threaded Apartment (Main() explicitly has the [MTAThread] attribute).
The main thread spawns some worker threads.
The main thread instantiates a single-threaded COM object.
The main thread calls Console.ReadLine() until the user hits 'q', after which the application terminates.
A few questions:
Numerous places mentions the need of a message pump for COM objects. Do I need to manually create a message-pump for the main thread, or will the CLR create it for me on a new STA thread, as this question suggests?
Just to make sure - assuming the CLR automagically creates the necessary plumbing, can I then use the COM object from any worker thread without the need of explicit synchronization?
Which of the following is better in terms of performance:
Let the CLR take care of the marshaling to and from the COM object.
Explicitly instantiate the object on a separate STA thread, and have other thread communicate with it via e.g. a ConcurrentQueue.
This is done automagically by COM. Since your COM object is single-threaded, COM requires a suitable home for the object to ensures it is used in a thread-safe way. Since your main thread is not friendly enough to provide such guarantees, COM automatically creates another thread and creates the object on that thread. This thread also automatically pumps, nothing you have to do to help. You can see it being created in the debugger. Enable unmanaged debugging and look in the Debug + Windows + Threads window. You'll see the thread getting added when you step over the new call.
Nice and easy, but it does have a few consequences. First off, the COM component needs to provide a proxy/stub implementation. Helper code that knows how to serialize the arguments of a method call so the real method call can be made on another thread. That's usually provided, but not always. You'll get a hard to diagnose E_NOINTERFACE exception if it is missing. Sometimes TYPE_E_LIBNOTREGISTERED, a common install problem.
And most significantly, every call on the COM component will be marshaled. That's slow, a marshaled call is usually around 10,000x slower than a direct call on a method that itself takes very little time. Like a property getter call. That can really bog your program down of course.
An STA thread avoids this and is therefore the recommended way to use a single-threaded component. And yes, it is a requirement for an STA thread to pump a message loop. Application.Run() in a .NET program. It is the message loop that marshals calls from one thread to another in COM. Do note that it doesn't necessarily mean that you must have a message loop. If no call ever needs to marshaled, or in other words, if you make all the calls on the component from the same thread, then the message loop isn't needed. That's typically easy to guarantee, particularly in a console mode app. Not if you create threads yourself of course.
One more nasty detail: a single-threaded COM component sometimes assumes it is created on a thread that pumps. And will use PostMessage() itself, typically when it uses worker threads internally and needs to raise events on the STA thread. That will of course not work correctly anymore when you don't pump. You normally diagnose this by noticing that events are not being raised. The common example of such a component is WebBrowser. Which heavily uses threads internally but raises events on the thread on which it was created. You'll never get the DocumentCompleted event if you don't pump.
So putting [STAThread] on your Main() method might be enough to get happy fast code, even without a call to Application.Run(). Just keep the consequences in mind, seeing a method call deadlock or an event not getting raised is the tell-tale sign that pumping is required.
Yes, it is possible to create a STA COM object from an MTA thread.
In this case, COM (not CLR) will create an implicit STA apartment (a separate COM-owned thread) or re-use the existing one, created ealier. The COM object will be instantiated there, then a thread-safe proxy object (COM marshalling wrapper) will be created for it and returned to the MTA thread. All calls to the object made on the MTA thread will be marshalled by COM to that implicit STA apartment.
This scenario is usually undesirable. It has a lot of shortcomings and may simply not work as expected, if COM is unable to marshal some interfaces of the object. Check this question for more details. Besides, the message pump loop, run by the implicit STA apartment, pumps only a limited number of COM-specific messages. That may also affect the functionality of the COM.
You may try it and it may work well for you. Or, you may run into some unpleasant issues like deadlocks, quite difficult to diagnose.
Here is a closely related question I just recently answered:
StaTaskScheduler and STA thread message pumping
I'd personally prefer to manually control the logic of the inter-thread calls and thread affinity, with something like ThreadAffinityTaskScheduler proposed in my answer.
You may also want to read this: INFO: Descriptions and Workings of OLE Threading Models, highly recommended.
Do I need to manually create a message-pump for the main thread,
No. It is in the MTA therefore no message pump is needed.
or will the CLR create it for me on a new STA thread
If COM creates the thread (because there is no STA in the process) then it also creates the message pump (and a hidden window: can be seen with the SPY++ and similar debugging tools).
COM object from any worker thread without the need of explicit synchronization
Depends.
If the reference to the single threaded object (STO) was created in the MTA then COM will supply the appropriate proxy. This proxy is good for all threads in the MTA.
In any other case the reference will need to be marshalled to ensure it has the correct proxy.
is better in terms of performance
The only answer to this is to test both and compare.
(Remember if you create the thread for the STA and then instantiate the object locally you need to do the message pumping. It is not clear to me that there is any CLR level lightweight message pump—including WinForms just for this certainly isn't.)
NB. The only in depth explanatory coverage of COM and the CLR is .NET and COM: The Complete Interoperability Guide by Adam Nathan (Sams, January 2002). But it is based on .NET 1.1 and now out of print (but there is a Kindle edition and is available via Safari Books Online). Even this book doesn't describe directly what you are trying to do. I would suggest some prototyping.
Related
I am working an SDK for a DSLR camera which has the following instructions:
Notes on Developing Windows Applications When creating applications
that run under Windows, a COM initialization is required for each
thread in order to access a camera from a thread other than the main
thread. To create a user thread and access the camera from that
thread, be sure to execute CoInitializeEx( NULL,
COINIT_APARTMENTTHREADED ) at the start of the thread and
CoUnInitialize() at the end. Sample code is shown below. This is the
same when controlling EdsVolumeRef or EdsDirectoryItemRef objects from
another thread, not just with EdsCameraRef.
void TakePicture(EdsCameraRef camera)
{
// Executed by another thread
HANDLE hThread = (HANDLE)_beginthread(threadProc, 0, camera);
// Block until finished
::WaitForSingleObject( hThread, INFINITE );
}
void threadProc(void* lParam)
{
EdsCameraRef camera = (EdsCameraRef)lParam;
CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
EdsSendCommand(camera, kEdsCameraCommand_TakePicture, 0);
CoUninitialize();
_endthread();
}
My application is a C# WinForms app and normally, I use the managed thread class and Control.Invoke functions to avoid cross-thread issues.
Since I do not have sample source code in C# for consuming the SDK, my question is, is it useful and/or necessary to use CoInitializeEx in an app marked with the [STAThread] attribute?
I have not come across a scenario were I would need to have my app create a new apartment for threads so some insight would be helpful to understand threading models better.
UPDATE: After reading some more about apartments and COM, it is beginning to make some sense. Now I'm wondering what the .NET managed thread class defaults to and can we specify an apartment model in a managed way to each thread without P/Invoke?
a COM initialization is required for each thread
Yes, rock-hard requirement. So much so that the CLR does this automatically without you having to help. Every .NET thread has CoInitializeEx() called before it starts running.
The CLR needs to know what argument to pass to CoInitializeEx(), selecting between STA and MTA. For the startup thread of your Winforms program it is determined by the [STAThread] attribute on your Main() method in Program.cs. It must be STA, a hard requirement for threads that display UI. For any thread that you start yourself it is determined by your call to Thread.SetApartmentState(), default is MTA. For any thread-pool thread, like the one used by BackgroundWorker or Task or QUWI, it is always MTA and cannot be changed. An automatic consequence of such a thread never being able properly support STA if it is used correctly.
Which is also what your code snippet is doing wrong, it is illegal to start an STA thread and not pump a message loop. You tend to get away with it by accident. Sometimes you do not and code will deadlock or fail in other ways, like not raising expected events. Since the vendor sanctioned it doing wrong, it probably does not matter here. But if you ever notice deadlock then you'd know where to look.
Long story short, you must not call CoInitializeEx() yourself, it was already done.
Extension to Release COM Object in C#
I noticed that saving the MailItem and releasing is a time consuming task. So, it is safe to do the following ? (pseudo-code below)
Thread 1 (main thread)
- Open 10 (different .msg files) - MailItems [List<MailItem> items]
- user works on them and want to save and close all of them with one click.
- On_save_All_click (runs on main thread)
- Do
- toBeClearedList.addAll(items);
- items.clear() [so that main thread cannot access those items]
- BG_Thread.ExecuteAsyn(toBeClearedList);
- End
Thread 2 (background thread) (input - List<MailItems>)
- foreach(MailItem item in input)
item.save();
System.Runtime.InteropServices.Marshal.ReleaseComObject(item)
- done
I wrote couple of tests and looks like its working; Just want to know if its safe to do so ? "Releasing COM objects in different thread than the one in which it was created"
Thanks
Karephul
When using COM from unmanaged code (C/C++), the rules are pretty strict: you can only call methods on an interface from the same apartment that you acquired the object on. So if you obtain an interface pointer on an STA thread, then only that thread is allowed to call any of the methods. If you obtain an interface pointer on an MTA thread, then only other threads in the same MTA can use that pointer. Any other use that crosses apartments requires that the interface pointer is marshaled to the other apartment.
However, that's unamanged world. .Net adds a whole layer on top of COM which buries a lot of these low-level details, and for the most part, once you get your hands on an interface, you can pass that interface around between threads as much as you please without having to worry about the old threading rules. What's happening here is that it are actually passing around references to an object called a "Runtime Callable Wrapper" (RCW), and it is managing the underlying COM interface, and controlling access to it accordingly. (It takes on the burden of upholding the COM apartment rules so that you don't have to, and that's why it can appear that the old COM threading rules don't apply in .Net: they do, they're just hidden from you.)
So you can safely call Release or other methods from another thread: but be aware that if the original thread was STA, then calling those methods will cause the underlying RCW to marshal the call back to the original owning thread so that it still upholds the underling COM rules. So using a separate thread may not actually get you any performance in the end!
Some articles worth reading that fill in some of the details here:
The mapping between interface pointers and runtime callable wrappers (RCWs) - good overview of some of the details of how RCW's work, but it doesn't say much about threading.
Improving Interop Performance - Marshal.ReleaseComObject - some good notes on when to use or not use ReleaseComObject, and how it works with the RCWs.
cbrumme's WebLog - Apartments and Pumping in the CLR - more internals than you're likely to want to know; this is a couple of CLR releases out of date, but still gives a good insight into how .Net covers over many of the underlying COM issues.
If I remember my COM properly (I always hated that technology, way too complicated), if the COM object is single-threaded (that is, belongs in a single-threaded-apartment), releasing it from another thread isn't going to do you any good - it's just going to execute the actual release code in your main thread.
You are going to see a little difference between your code, and releasing the objects from the main thread in one loop. If you release the objects in one loop, your UI is going to be unresponsive until you release all messages. By using a secondary thread, your UI thread will release one message, then handle other events, then release another, and so on. You can get the same effect by sending yourself a message (or using a Dispatcher if you have a WPF application), and avoid having another thread.
I got this(the error in the title above) from the System.Thread.Timer threadpool so then I have my TimerWrapper that wraps the System.Thread.Timer to move the actual execution to System.Thread.ThreadPool and I still get it so I move it a new Thread(callback).Start() and I still get it. How is it dispatching an input-synhcronous call when I put it on a brand new thread???
This is a very very small prototype app in which all I am doing is firing a timer that is doing this...
IEnumerable swc = SHDocVw.ShellWindows()
HashSet<WindowInfo> windows = new HashSet<WindowInfo>();
foreach (SHDocVw.InternetExplorer ie in swc)
{
if (!ie.FullName.ToLower().Contains("iexplore.exe"))
continue;
IntPtr hwnd;
IEPlugin.IOleWindow window = ie.Document as IEPlugin.IOleWindow;
window.GetWindow(out hwnd);
WindowInfo info = new WindowInfo();
info.handle = hwnd;
info.extraInfo = ie;
windows.Add(info);
}
Congratulations; you've managed to stumble on one of my favourite COM quirks, in this case, a delightfully obscure restriction with IOleWindow's GetWindow method - and an error message that gives you little clue as to what's going on. The underlying problem here is that the GetWindow() method is marked as [input_sync] - from the include\oleidl.idl file in the SDK:
interface IOleWindow : IUnknown
{
...
[input_sync]
HRESULT GetWindow
(
[out] HWND *phwnd
);
Unfortunately, the docs for IOleWindow don't mention this attribute, but the docs for some others, such as IOleDocumentView::SetRect() do:
This method is defined with the [input_sync] attribute, which means that the view object cannot yield or make another, non input_sync RPC call while executing this method.
The idea behind this attribute is to guarantee to the caller (which could be an app like Word or some other OLE control host) that it can safely call these methods without having to worry about reentrancy.
Where things get tricky is that COM decides to enforce this: it will reject cross-apartment calls to an [input_sync] method if it thinks it could violate these constraints. So, IIRC, you can't do a cross-apartment [input_sync] call if you are within a SendMessage() - that's the case the error message is somewhat alluding do. And - this is the one that's getting you here - you can't call a cross-apartment [input_sync] method from an MTA thread. Perhaps COM is being a bit over-zealous in its enforcement here, but that's what you have to deal with anyhow.
(Brief comment on MTA vs STA threads: in COM, threads and objects are either STA or MTA. STA, Single-Threaded-Aparment, is the way Windows UI works; a single thread owns the UI and all objects associated with it, and those objects expect to get called by that thread alone. MTA, or Multi-Threaded-Aparment, is more of a free-for-all; objects can expect to be called from any thread at any time, so need to do their own synchronization to be thread-safe. MTA threads are usually used for worker and background tasks. So you may manage UI on a single STA thread, but download a bunch of files in the background on using one or more MTA threads. COM does a bunch of work to allow the two to interop with each other and attempts to hide some of the complexity. Part of the issue here is you're mixing these metaphors: ThreadPools are associated with background work so are MTA, but IOleWindow is UI-centric, so is STA - and GetWindow happens to be the one method that is really really strict about enforcing this.)
Long story short, you can't call this method from a ThreadPool thead because they are MTA threads. Also, new threads are MTA by default, so just creating a new thread to do the work on is insufficent.
Instead, create the new thread, but use tempThread.SetApartmentState(ApartmentState.STA); before starting it, this will give you an STA thread. You may need to actually put all of the code that deals with the shell COM object in that STA thread, not just the single call to GetWindow() - I don't remember the exact details offhand, but if you end up acquiring the original COM object (seems to be the ShellWindows one here) while on the MTA ThreadPool thread, it will stay associated with that MTA even if you attempt to call it from a STA.
If you could instead do all the work from an STA thread rather than a MTA one from the ThreadPool, so much so the better, that would avoid this in the first place. Rather than using System.Threading.Timer, which is designed for background/non-UI code, try using the UI-centric System.Windows.Forms.Timer instead. This does require a message loop - if you've already got windows and forms in your app, you've already got one, but if not, the simplest way to do this in test code is to do a MessageBox() in the same place where your main line code is waiting to exit (usually with a Sleep or Console.ReadLine or similar).
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) ?
then it cannot run code marked with [MTAThread] attribute.
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.
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.
From the MSDN article on STAThread:
Indicates that the COM threading model for an application is single-threaded apartment (STA).
(For reference, that's the entire article.)
Single-threaded apartment... OK, that went over my head. Also, I read somewhere that unless your application uses COM interop, this attribute actually does nothing at all. So what exactly does it do, and how does it affect multithreaded applications? Should multithreaded applications (which includes anything from anyone using Timers to asynchronous method calls, not just threadpools and the like) use MTAThread, even if it's 'just to be safe'? What does STAThread and MTAThread actually do?
Apartment threading is a COM concept; if you're not using COM, and none of the APIs you call use COM "under the covers", then you don't need to worry about apartments.
If you do need to be aware of apartments, then the details can get a little complicated; a probably-oversimplified version is that COM objects tagged as STA must be run on an STAThread, and COM objects marked MTA must be run on an MTA thread. Using these rules, COM can optimize calls between these different objects, avoiding marshaling where it isn't necessary.
What that does it it ensures that CoInitialize is called specifying COINIT_APARTMENTTHREADED as the parameter. If you do not use any COM components or ActiveX controls it will have no effect on you at all. If you do then it's kind of crucial.
Controls that are apartment threaded are effectively single threaded, calls made to them can only be processed in the apartment that they were created in.
Some more detail from MSDN:
Objects created in a single-threaded
apartment (STA) receive method calls
only from their apartment's thread, so
calls are serialized and arrive only
at message-queue boundaries (when the
Win32 function PeekMessage or
SendMessage is called).
Objects created on a COM thread in a
multithread apartment (MTA) must be
able to receive method calls from
other threads at any time. You would
typically implement some form of
concurrency control in a multithreaded
object's code using Win32
synchronization primitives such as
critical sections, semaphores, or
mutexes to help protect the object's
data.
When an object that is configured to
run in the neutral threaded apartment
(NTA) is called by a thread that is in
either an STA or the MTA, that thread
transfers to the NTA. If this thread
subsequently calls CoInitializeEx, the
call fails and returns
RPC_E_CHANGED_MODE.
STAThread is written before the Main function of a C# GUI Project. It does nothing but allows the program to create a single thread.