每个线程都关联了一个执行上下文数据结构。执行上下文(execution context)包含的东西有安全设置(压缩栈,Thread的Principal 属性和windows身份)、宿主设置以及逻辑调用上下文数据的LogicSetData和LogicalGetData 方法。线程执行代码时,有的操作会受到线程的执行上下文设置的影响。理想情况下,每当一个线程使用另一个线程执行任务时,前者的执行上下文应该流向辅助线程。这就确保了辅助线程执行的任何操作使用的是相同的安全设置和宿主设置。还确保了初始线程的逻辑调用上下文可以在辅助线程中使用。
默认情况下,CLR自动造成了初始线程的执行上下文或任何辅助线程“流”去。这就将上下文信息传输到了辅助线程,但这会对性能造成一定影响,因为执行上下文包含大量的信息,而收集所有这些信息,再把它们复制到辅助线程,要耗费不少时间。如果辅助线程又采用了更多的辅助线程,还必须创建和初始化更多的执行上下文数据结构。
System.Threading 命名空间中有一个 ExecutionContext类,它允许你控制线程的执行上下文如何从一个线程“流”向另一个。下面展示了这个类的样子
public sealed class ExecutionContext : IDisposable,ISerializable{
[SecurityCritical] public static AsyncFlowControl SuppressFlow();
public static void RestoreFlow();
public static Boolean IsFlowSuppressed();
}
可用这个类阻止一个执行上下文的流动,从而提升应用程序的性能。对于服务器应用程序,性能的提升非常显著。但是,客户端应用程序的性能提升不了多少。另外,由于SuppressFlow 方法用 [SecurityCritical] attribute进行了标识,所以在某些客户端应用程序中是无法调用的。当然,只有在辅助线程不需要或者不访问上下文信息时,才应阻止执行上下文的流动。如果初始线程的执行上下文不流向辅助线程,辅助线程会使用和它关联的任何执行上下文。在这种情况下,辅助线程不应执行任何要依赖于执行上下文状态的代码。
下例展示了向CLR的线程池队列添加一个工作项的时候,如何通过阻止上下文的流动来影响线程逻辑调用上下文的数据:
public static void Main(){
//将一些数据放到Main线程的逻辑调用上下文中
CallContext.LogicalSetData("Name", "Jeffrey");
ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
// 现在,阻止Main线程的执行上下文的流动
ExecutionContext.SuppressFlow();
// 初始化要由一个线程池线程做的一些工作,
// 线程池线程不能访问逻辑调用上下文数据。
ThreadPool.QueueUserWorkItem(state => Consloe.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));
ExecutionContext.RestoreFlow();
}