I have a problem in a utility library, which does some COM interop. It keeps references to COM objects which are used between calls.
If all methods are called from threads using the same COM threading model, the class works fine.
But if the calls that create COM objects use a different threading model than used for subsequent calls, QueryInterface fails with E_NOINTERFACE.
We only found this when we added async branches to our unit tests; prior to this it was running fine in all-MTA apps all-STA unit tests...
I think I understand the reason for the failure (via COM docs, Chris Brumme's blog) - the COM objects being used support "both" threading models which causes C# to create a fence between the STA and MTA-created instances.
However from the library's point of view, the only fixes I can think of are a bit rubbish:
Make it an unwritten rule that this library is for MTA threads only
Change the library to detect calls from STA threads and fail (using e.g. CurrentThread.ApartmentState)
Change the library to create its own MTA threads for all COM interop (or perhaps just when incoming calls are on an STA thread)
Are there any cleaner/easier options? Here's a MCVE:
class Program
{
[ComImport, Guid("62BE5D10-60EB-11d0-BD3B-00A0C911CE86")] class SystemDeviceEnum { };
[ComVisible(true), ComImport, Guid("29840822-5B84-11D0-BD3B-00A0C911CE86"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ICreateDevEnum { [PreserveSig] int CreateClassEnumerator([In] ref Guid pType, [Out] out IEnumMoniker ppEnumMoniker, [In] int dwFlags); }
static ICreateDevEnum createDeviceEnum;
static Guid VideoInputDeviceCategory = new Guid("860BB310-5D01-11d0-BD3B-00A0C911CE86");
static void Prepare()
{
var coSystemDeviceEnum = new SystemDeviceEnum();
createDeviceEnum = (ICreateDevEnum)coSystemDeviceEnum;
}
static int GetDeviceCount()
{
IEnumMoniker enumMoniker;
createDeviceEnum.CreateClassEnumerator(ref VideoInputDeviceCategory, out enumMoniker, 0);
if (enumMoniker == null) return 0;
int count = 0;
IMoniker[] moniker = new IMoniker[1];
while (enumMoniker.Next(1, moniker, IntPtr.Zero) == 0) count++;
return count;
}
[STAThread]
static void Main(string[] args)
{
RunTestAsync().Wait();
}
private static async Task RunTestAsync()
{
Prepare();
await Task.Delay(1);
var count = GetDeviceCount();
Console.WriteLine(string.Format("{0} video capture device(s) found", count));
}
}
COM threading is notoriously poorly understood. Actually much, much easier to get going than threading .NET classes. Just about everybody knows that, say, the List<> or Random class is not thread-safe. Not that many know how to use them in a thread-safe way. The COM designers had much loftier goals and assumed that programmers in general don't know how to write thread-safe code and that the Smart People should take care of it.
It does require taking care of a few details. First and foremost, you must tell COM what kind of support you are willing to provide to coclasses that are not thread-safe but are used from a worker thread anyway. And there you committed a horrible, horrible crime. When you use [STAThread] then you make a promise. Two things you must do: you must never block the thread and you must pump a message loop (aka Application.Run). Note how you broke both requirements. Never ever lie about it, very bad things happen when you do. But you didn't get that far yet.
The kind of threading support you can expect from the coclass you are using is easy to discover. Start up Regedit.exe and navigate to HKLM\Software\Wow6432Node\Classes\CLSID. Locate the {guid} you use and look at the ThreadingModel value you see in the InProcServer32 key. It is "Both" for the one you are using. Means that it was written to work both from an STA thread and a thread that doesn't support thread-safety at all and runs in the MTA. Like your main thread and your Task. And as you discovered, it works fine from either. Do beware that this isn't very usual, the vast majority of COM servers only support the "Apartment" threading model. Microsoft usually goes the extra thousand miles to support both.
So you created the enumerator object on an STA thread and use it on a thread in the MTA. Now the COM runtime must do something quite non-trivial, it must make sure that any callbacks (aka events) that might be invoked from the method you call run on the same STA thread so that any code in the callback is thread-safe as well. In other words, it must marshal the call from the worker thread back to your main thread. The equivalent of Control.Invoke or Dispatcher.Invoke in a .NET app. Done completely automatically in COM.
That requires doing something that's very easy in .NET but very hard in unmanaged code. The arguments of the method must be copied from one stack frame to another so the call can be made on the other thread. Easy to do in .NET thanks to Reflection. Not nearly as easy to do for unmanaged code, it requires an oracle that knows what the method parameter types are, a substitute for the missing metadata.
That oracle is found in the registry as well. Use Regedit and navigate to the HKLM\Software\Wow6432Node\Classes\Interface key. Locate the interface guid there, {29840822-5B84-11D0-BD3B-00A0C911CE86} as the exception message tells you. You'll notice the problem: it isn't there. Yes, the exception message is pretty lousy. The real E_NOINTERFACE is reported because the COM runtime can't find another way either, no support for IMarshal. If it would be there then you'd get to deal with the [STAThread] lie, your thread will deadlock.
That's unusual btw, COM object models that use a ThreadingModel of "Both" almost always also support marshaling. Just not for the specific one you are trying to use. DirectShow has been deprecated for the past 10 years and replaced by Media Foundation. You found one good reason why Microsoft decided to retire it.
So this is just something you need to know. A detail that isn't very different from having to know that the Random class isn't thread-safe. It is not well documented in MSDN, but as noted it is easy to discover by yourself.
Related
I am writing a Win32 C++ DLL that uses the COM object(B.dll) which is made in C#.
This dll(A.dll) provides CMyComObject class which creates a COM object and access to it.
Here is my code.
void CMyComObject::CMyComObject()
{
HRESULT result = CoInitialize(NULL);
...
result = CoCreateInstance(CLSID_COMDLL, NULL, CLSCTX_INPROC_SERVER, IID_COMDLL, reinterpret_cast<void**>(&MyComObject));
}
void CMyComObject::~CMyComObject()
{
..
CoUninitialize();
..
}
And then, here is a client program that loads A.dll and access to the COM object.
This program creates several threads which load A.dll and create a COM object concurrently.
In this case, Is this correct to use CoInitialize() function or Should I use CoInitializeEx() function with COINIT_MULTITHREADED parameter?
Or Is there any mistake I did?
(I registered B.dll by commanding "reg_asm.exe B.dll B.tlb /codebase")
Sorry for my poor English.
Thanks.
You are supposed to use CoInitialize[Ex]/CoUninitialize before and after any COM activity on that thread, and your choice between CoInitialize and CoInitializeEx with specific parameters depends on whether you prefer STA or MTA mode for your thread.
Having said that, your initialization:
Does not depend on whether the COM object itself creates any threads
Does not depend on other parts of your application possibly having other COM activity, including similar instantiation of the same COM class
Entirely depends on your COM activity on the thread in question
Does not normally happen in class constructor; it is typical to have COM initialization associated with top level thread code such as before windows message pump or at the very beginning of the thread procedure; putting it into constructor is an easy way to get into collision e.g. with another initialization (esp. using different apartment model) or too early uninitialization.
Summing it all once again, your initialization:
looks good if you are OK with COM single thread apartment model and you don't pass obtained pointer between threads
you would be better off moving CoInitialize and CoUninitialize calls out of constructor and associate it with thread code
be sure to check returned value to detect failures, esp. attempt to initialize mismatching apartment on the thread already having COM initialization
the part you missing is that you have to close all your COM activity before CoUninitialize call, including releasing your MyComObject pointer.
I have a 3rd party library that offers a class. Their documentation says:
Thread Safety
Public static (Shared in Visual Basic) members of this type are safe for multithreaded operations. Instance members are not guaranteed to be thread-safe.
I did some testing where I created 100 threads. Indeed there are thread safety issues if I pass the same object to all 100 threads, but those problems appear to go away if each thread creates its own instance of the class.
I'm using .NET 4.0 here. In my application there are multiple threads that will want to use this class, but I don't want to create and destroy the objects more than necessary (they should live for the lifetime of the application), so I want one per thread. Is this an appropriate use of the ThreadLocal<T> class? If not, what is the standard way to handle this?
Edit:
Some more information about the 3rd party class. It's a communication library and opens a communication link to another process, either on this computer or another computer. The other end of the communication link is designed to accept concurrent connections. Therefore I shouldn't need to synchronize the method calls on my end by using locks. However, each instance is not thread safe.
Assuming you don't need the objects to interact with each other at all, ThreadLocal<T> is a very good choice here. It obviously doesn't work if modifications made in one thread are meant to be seen in another thread, just safely.
Yes, it will create one object per thread - but unless creating the objects is really expensive, you're likely to have on the order of hundreds of instances, which in most cases is absolutely fine.
One classic example of this is System.Random:
You don't want to create instances on an ad hoc basis, as if you're not careful you'll end up with multiple instances with the same seed
It's definitely not thread-safe.
So you could do something like:
public static class RandomProvider
{
private static readonly Random seedProvider = new Random();
private static readonly ThreadLocal<Random> threadLocal =
new ThreadLocal<Random>(InitializeNewRandom);
public static Random GetRandomForThread()
{
return threadLocal.Value;
}
private static Random InitializeNewRandom()
{
lock(seedProvider)
{
return new Random(seedProvider.Next(int.MaxValue));
}
}
}
An alternative would be to write a thread-safe proxy class which used locking for each operation - but that still has issues if you have multiple operations which you wish to execute "atomically" (i.e. without interleaving other calls).
I think that making a wrapper above this class which blocks all operations with Monitors( lock keyword) or other thread blocking sync construct can help.
But it does not guarantee absence of possible deadlocks and race conditions. Without complete rewrite of the original class and its consumers you may still run into a problem.
You can't make unsafe thing safe and unsecure thing secure in postprocessing. Such qualities must be considered at first and this is even not your library.
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.
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).