6

It's not a question of major importance, but I was wondering why the Thread class exposes a property for getting the current Context (Thread.CurrentContext) and a method for getting the current AppDomain (Thread.GetDomain()).

Knowing the hierarchy of Process > AppDomain > Context > Thread, my assumption would be that the context for thread is known at current point in time, and the domain needs to be searched based on current context.

But I'd like to hear wiser answers. Thanks!

Ani
  • 2,636
  • 1
  • 21
  • 17
  • 1
    I'm pretty certain your understanding of the hierarchy is wrong. A thread observes a context. – Gusdor Mar 31 '14 at 08:57
  • `Thread` and `Context` are independent entities. A `Context` is something associated with `ContextBoundObject`-objects, not threads. Multiple contexts can flow through the same thread (with `Context.DoCallBack`), and multiple threads can share the same context (`Thread.CurrentContext`). You cannot though "move" a thread to another domain. Related: http://stackoverflow.com/q/22416182/1768303. – noseratio Mar 31 '14 at 09:55
  • @Noseratio Of course you can "move" a thread to another domain. From _Andrew Troelsen's Pro C# 5.0 and the .NET 4.5 Framework_: "Threads are free to cross **application domain** boundaries as the Windows OS thread scheduler and the .NET CLR see fit." – Ani Mar 31 '14 at 10:20
  • @Gusdor About the thread-context relationship, again from _Andrew Troelsen's Pro C# 5.0 and the .NET 4.5 Framework_: "A single thread may also be moved into a particular **context** at any given time, and it may be relocated within a new context at the whim of the CLR." So my understanding of the hierarchy is pretty accurate. – Ani Mar 31 '14 at 10:21
  • Just use a decent decompiler to see these members being used heavily inside the .NET Framework itself. The most obvious use for GetDomain() is AppDomain.CurrentDomain, they both get used heavily in the Remoting glue. – Hans Passant Mar 31 '14 at 11:42
  • @Ani, I am aware that it's possible to enter another domain on the same thread with `AppDomain.DoCallBack`. Although I stand corrected: there is no parent-child relationship between domain and thread, unlike I thought there would be. – noseratio Mar 31 '14 at 12:31
  • @Ani, no you can't move threads to another domain. You have no control over clr and OS thread scheduling. As you correctly pointed out they can do this as they see fit, but you can't. – Andrew Savinykh Apr 01 '14 at 06:49
  • @Ani also I think there is a difference between windows thread and CLR thread. What is said above is correct for windows thread, but I'm not so sure about the CLR ones (which are implemented on top of windows ones). Can you think of a case when a CLR thread (not windows thread) crosses an appdomain boundary? – Andrew Savinykh Apr 01 '14 at 06:54
  • @zespri Not that I can think of right now. Appdomain boundary crossing would require deep usage of threads and I'm not a guru of it actually :) – Ani Apr 01 '14 at 13:05

1 Answers1

6

my assumption would be that the context for thread is known at current point in time, and the domain needs to be searched based on current context.

Indeed, in the current implementation of the .NET Framework the Context object keeps a reference to its parent domain. The Framework designers might have exposed the context's domain as Thread.Context.Domain. It probably would be a rhetorical question why they didn't do so; I can't tell that by looking into the reference source code.

What matters is that at any given moment of time, the thread is executing code inside a particular domain. This would be either the process's default domain, or the domain entered via AppDomain.DoCallBack, AppDomain.ExecuteAssembly or a marshalled MarshalByRefObject-object. That'd would be the domain Thread.GetDomain() returns.

This domain has at least one context (the default one), but it may also have other contexts, created for ContextBoundObject-objects. It's possible to enter any of those contexts explicitly on the same domain via Context.DoCallBack or implicitly from any domain by calling a marshalled ContextBoundObject-object. That'd be the context Thread.Context returns.

There is no parent-child relationship between thread and domain or thread and context. However, there is strict parent-child, one-to-many relationship between domain and its contexts. So, the domain doesn't need to be searched based on current context.

If you like to play with it a bit more, here is the app I used:

using System;
using System.Runtime.Remoting.Contexts;
using System.Threading;

namespace ConsoleApplication
{
    public class Program
    {
        [Synchronization]
        public class CtxObject : ContextBoundObject
        {
            public void Report(string step)
            {
                Program.Report(step);
            }
        }

        public static void Main(string[] args)
        {
            Program.Report("app start");
            System.AppDomain domain = System.AppDomain.CreateDomain("New domain");

            var ctxOb = new CtxObject();
            ctxOb.Report("ctxOb object");

            domain.SetData("ctxOb", ctxOb);
            domain.DoCallBack(() => 
            {
                Program.Report("inside another domain");
                var ctxOb2 = (CtxObject)System.AppDomain.CurrentDomain.GetData("ctxOb");
                ctxOb2.Report("ctxOb called from another domain");
            });

            Console.ReadLine();
        }

        static void Report(string step)
        {
            var threadDomain = Thread.GetDomain().FriendlyName;
            Console.WriteLine(
                new
                {
                    // Thread.CurrentContext.ContextID is only unique for the scope of domain
                    step,
                    ctx = Thread.CurrentContext.GetHashCode(),
                    threadId = Thread.CurrentThread.ManagedThreadId,
                    domain = Thread.GetDomain().FriendlyName,
                });
        }
    }
}
noseratio
  • 59,932
  • 34
  • 208
  • 486