Given: Constructing an ADO Connection object from one thread and giving it to another thread is forbidden. The two threads are different apartments, and even though the first thread will never touch it again (not even maintain a reference to it!), it doesn’t matter.
That ADO Connection object was created by ThreadA, ThreadA is the only thread, ever, under any circumstances, at all, ever, that is allowed to use that Connection object, ever.
Now replace ‘ADO Connection’ with ‘ADO.NET Connection’. Does the same rule apply?
i know that most objects in the .NET framework are not thread-safe. For example, the DictionaryEntry structure in the SDK says:
Thread Safety
Any public static members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
i understand that not thread-safe means that i have to synchronize access to the object if i am going to access it from different threads. That’s all well and good, and i could ensure only one thread access the object at a time:
lock (myObject) { ... }
But there’s something more than not being thread-safe.
In COM, (some) objects are bound to the ‘apartment‘ that created it. Once the object has been constructed on one apartment, you are forbidden from accessing it from another apartment – no matter how much you protect that object from multiple simultaneous thread access.
Does a similar concept exist in .NET?
More Information
i know you are forbidden from accessing Controls from threads other than the one that created it – even if you use it in a thread-safe manner. This is not documented on MSDN:
Thread Safety
Only the following members are thread safe: BeginInvoke, EndInvoke, Invoke, InvokeRequired, and CreateGraphics if the handle for the control has already been created. Calling CreateGraphics before the control’s handle has been created on a background thread can cause illegal cross thread calls.
There is no mention of Controls throwing exceptions when you create and use them from a single thread – when that thread is not the first thread that was created when the application started.
But what about arbitrary objects? What about:
public class MyClass { int _number; public int Number { get { return _number; } set { _number = value; } } } MyClass myObject = new MyClass();
As long as i synchronize access to myObject two threads are allowed to talk to it?
The same goes for:
List<Object> sharedList = new List<Object>();
Two threads can talk to the list, as long as they don’t do it simultaneously, usually with:
lock (sharedList) { sharedList.Add(data); }
are two threads allowed to touch the same object?
The same goes for:
IAsyncResult ar = BeginSetLabelToTheValueINeed(label1); ... EndSetLabelToTheValueINeed(ar);
The same goes for:
//Fetch image on connection that is an existing DB transaction public static Bitmap GetImageThumbnail(DbConnection conn, int imageID) { }
being converted into the asynchronous delegate pattern:
//Begin fetching an image on connection that is an existing DB transaction IAsyncResult ar = BeginGetImageThumbnuts(conn, imageID, callback, stateOjbect); ... //Finish fetching an image on connection that is an existing DB transaction Bitmap thumb = EndGetImageNumbthail(ar);
Rather than answering the question, people went off on a discussion about design patterns in ADO.NET. Please answer the question. Ignore the examples if they confuse and distract your squirrel brains.
SHOOTING for the bounty!
Okay, some classes/frameworks of classes in .NET have methods that are apartment bound, but BY DESIGN ONLY. That means you have to SPECIFICALLY CODE to do this. Its not set by default. Coding for this is kinda kludgy. You have to get the thread ID you want to stick with and check it all the time. I don’t think there are any facilities in the framework that makes this easy, other than those for UI components tracking the UI thread. That support framework is probably buried deep within the UI stack; I’ve never seen it in any MSDN docs.
What IS more common is setting the thread apartment. Lots of parts of the entire framework are restricted to STA threads by design (STAThreadAttribute). This is usually because they, deep down in their core, touch COM objects which often require that they are only used in STA threads. For example, the main thread in winforms apps is marked with the STAThreadAttribute, so that every UI component can only be touched within the same thread they are created, the UI thread. Interestingly, the XamlReader in WPF is aware of the current thread apartment and won’t even deserialize UI components unless the thread its running in is an STA thread.
‘Does a standard POCO have thread affinity or care if its in a STA or MTA thread?’ The answer is no, unless you code it to be so or mark its methods with the STAThreadAttribute or if the object is instantiated in a call stack that, somewhere in its hierarchy, has a method marked with the STAThreadAttribute.
‘Does an ADO.NET object have thread affinity, and is it apartment aware?’
Well, a DbConnection extends from Component, which extends MarshalByRefObject. Component, MBRO, DbConnection and its descendents (i.e., SqlConnection) contain no methods that are marked with the STAThreadAttribute. A quick check of their major dependencies (such as DbTransaction) doesn’t find that any of THOSE classes’ methods are marked as STA only as well. Therefore they are not apartment aware.
A quick browse with Reflector doesn’t find any obvious thread-id watching. DbConnection does depend on Transaction, which seems like the most likely thread-fondler of the bunch.
I busted out Reflector and checked out a few of these classes.
DbConnection – Doesn’t care about the current thread’s ID
SqlConnection – Does some thread tracking when debugging
SqlTransaction – Has a function called ‘ZombieCheck’, but no thread watching
DbTransaction – Nothing here.
So I think its safe to say that ADO.NET objects do NOT have thread affinity. I didn’t even see them use Thread.Begin/EndThreadAffinity.
EDIT
As pointed out in the comments by Jeremy, I kept talking about the CLASSES being marked with the attribute rather than the CLASSES’ METHODS. HUUUGE mistake. I screwed up bigtime by giving the impression that I only looked at the class definitions rather than the entire class.
I’ve edited this to clarify, and let me say it here to be absolutely clear: No class methods in System.Data are marked with the STAThreadAttribute. You can check this for yourself with the following hacky code:
Also, UI classes in winforms also don’t use the STAThreadAttribute; its the application where this attribute is used (as, again, Jeremy pointed out).
There is a special case where I’ve run into a class being apartment aware. The XamlReader, which deserializes xaml and creates WPF UI classes, will throw an exception when its Load method is called on a MTA thread. Its not even in the docs, which is annoying… So, again, classes aren’t apartment aware by default; you have to code it that way or you have to make their instances aware by newing them up in a method chain containing a method marked by the STAThreadAttribute. Whew. This stuff is harder to explain than understand…