During a thread on the Microsoft C#
newsgroups someone was asking about whether they could use a Monitor for cross
process synchronization. I replied stating that a Monitor was AppDomain
specific and so no. Willy Denoyette (do you have a blog Willy?) replied and
said “If you take a lock on a domain neutral type, you will get a
cross-domain lock”. I’d completely forgotten about Domain Neutral assemblies
and so it was great that Willy jumped in. However, I wanted to chase down the
exact implications of this as Willy’s statement can be interpreted a couple of
different ways.
So here is my test harness.
using System;
using System.Threading;
class App
{
static object o = typeof(string);
static void Main(string[] args)
{
AppDomain ad = AppDomain.CreateDomain("foo");
ad.DoCallBack(new CrossAppDomainDelegate(Bar));
Quux();
}
public static void Bar()
{
Thread th = new Thread(new ThreadStart(Quux));
th.Start();
}
static void Quux()
{
Thread.Sleep(1000);
lock(o)
{
Console.WriteLine("In loc {0}",
AppDomain.CurrentDomain.FriendlyName);
Thread.Sleep(3000);
}
Console.WriteLine("Out of lock");
}
}
In Main I
call Bar in the other AppDomain.
Bar calls Quux on another thread
(so I can make the two blocks of code compete for what should be a common
Monitor). Then I call Quux from Main in the default AppDomain.
Now, you should note that mscorlib
is loaded domain neutral (only one copy is JIT’d and statics are shared across
AppDomains. So for this exercise I will only use types from mscorlib.
I started off using the type object of System.String (as you can see above).
This indeed exhibited the behavior Willy identified that this can be used as a
cross-AppDomain locking target. This means the type object of types in domain
neutral assemblies are shared by all AppDomains (which isn’t a problem as they
are non-volatile).
Next I switched the line initializing o to
static object o =new object();
So now this is an instance of a type from an assembly loaded
domain neutral. This resulted in no synchronization between the two AppDomains –
and hopefully this is no great shock as most objects do not transcend AppDomain
boundaries.
Now I switched to
static object o = typeof(App);
In other words, the type object of a type from a non-domain
neutral assembly. This again gave no synchronization. Again, hopefully, not a
shocking result.
Finally, what about statics, are they treated in any special way?. We need to find a type in mscorlib that has a public static
property or field to get make this test case. Enter Environment.OSVersion a demand allocated reference type.
Changing my line again I get:
static object o = Environment.OSVersion;
And again no synchronization. Type objects are shared cross domain for domain neutral types - this is a special case and is known as Marshal-By-Bleed.
Interned strings are also shared across AppDomains. In general, however, objects are not shared cross domain under any other circumstances.