为什么要使用 Thread.CurrentContext 属性和 Thread.GetDomain() 方法?

6

这不是一个非常重要的问题,但我想知道为什么Thread类会公开一个用于获取当前上下文(Thread.CurrentContext)的属性和一个用于获取当前AppDomain(Thread.GetDomain())的方法。

了解进程(Process) > 应用程序域(AppDomain) > 上下文(Context) > 线程(Thread)的层次结构,我的假设是线程的上下文在当前时间点已知,需要根据当前上下文搜索应用程序域。

但我想听到更明智的答案。谢谢!


1
我非常确定你对层次结构的理解是错误的。一个线程观察一个上下文。 - Gusdor
ThreadContext是独立的实体。Context是与ContextBoundObject对象相关联的东西,而不是线程。多个上下文可以通过同一个线程流动(使用Context.DoCallBack),多个线程也可以共享同一个上下文(Thread.CurrentContext)。但是您无法将线程“移动”到另一个域中。相关链接:https://dev59.com/VX3aa4cB1Zd3GeqPfqCs。 - noseratio - open to work
@Gusdor 关于线程上下文关系,再次引用《Pro C# 5.0和.NET 4.5 Framework》中的_Andrew Troelsen_所说:“单个线程也可以在任何时候移动到特定的上下文中,并且它可能会在CLR的心血来潮下被重新定位到新的上下文中。” 因此,我对层次结构的理解是相当准确的。 - Ani
只需使用一个不错的反编译器,就可以看到这些成员在.NET Framework内部被广泛使用。 GetDomain()最明显的用途是AppDomain.CurrentDomain,在Remoting粘合剂中它们都被广泛使用。 - Hans Passant
@Ani,不,你不能将线程移动到另一个域。你无法控制clr和操作系统的线程调度。正如你正确指出的那样,他们可以根据自己的意愿进行操作,但你不能这样做。 - Andrew Savinykh
显示剩余4条评论
1个回答

6

我的假设是,当前上下文中已知线程的上下文,并且需要基于当前上下文搜索域。

实际上,在.NET Framework的当前实现中,Context对象保留对其父域的引用。框架设计人员可能已将上下文的域公开为Thread.Context.Domain。很可能会有一个反问句,即为什么他们没有这样做;通过查看参考源代码,我无法得知。

重要的是,在任何给定时间点,线程都在特定域内执行代码。这将是进程的默认域,或者通过AppDomain.DoCallBackAppDomain.ExecuteAssembly或一个已封送的MarshalByRefObject对象进入的域。这将是Thread.GetDomain()返回的域。

这个域至少有一个上下文(默认上下文),但也可能有其他为ContextBoundObject对象创建的上下文。可以通过Context.DoCallBack显式地进入同一域中的任何上下文,或者通过调用已编组的ContextBoundObject对象从任何域中隐式进入。 这就是Thread.Context返回的上下文。 线程与域或上下文之间没有父子关系。但是,域和其上下文之间存在严格的父子关系。 因此,不需要基于当前上下文搜索域。 如果您想更多地玩一下,这是我使用的应用程序:
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,
                });
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接