网上关于ExecutionContext的说明比较少,我们来看看微软的描述吧,

  名称 说明
Capture()

捕获从当前线程的执行上下文。

CreateCopy()

创建当前执行上下文的副本。

Dispose()

释放 ExecutionContext 类的当前实例所使用的所有资源。

Equals(Object)

确定指定的对象是否等于当前对象。(继承自 Object。)

GetHashCode()

作为默认哈希函数。(继承自 Object。)

GetObjectData(SerializationInfo, StreamingContext)

设置指定 SerializationInfo 重新创建当前执行上下文的实例所需的逻辑上下文信息的对象。

GetType()

获取当前实例的 Type。(继承自 Object。)

IsFlowSuppressed()

指示是否当前正在取消执行上下文的流动。

RestoreFlow()

在异步线程间恢复执行上下文的流动。

Run(ExecutionContext, ContextCallback, Object)

在当前线程上指定的执行上下文中运行的方法。

SuppressFlow()

在异步线程间取消执行上下文的流动。

ToString()

返回表示当前对象的字符串。(继承自 Object。)

而实际开发中我们用的比较多的应该是SuppressFlow,RestoreFlow,Capture,CreateCopy和Run方法,比如我们在一个Barrier源码中,调用回调方法就是采用ExecutionContext 的Run方法,但是该方法需要一个ExecutionContext 实例,于是我们需要先捕获一个ExecutionContext 实例,然后拷贝再传递给Run方法,而有些时候我们又不想同步上下文,可以用SuppressFlow来暂停同步。这里需要借助一个AsyncFlowControl结构:

public struct AsyncFlowControl: IDisposable
{
private bool useEC;
private ExecutionContext _ec;
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
private SecurityContext _sc;
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
private Thread _thread;
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
[SecurityCritical]
internal void Setup(SecurityContextDisableFlow flags)
{
useEC = false;
Thread currentThread = Thread.CurrentThread;
_sc = currentThread.GetMutableExecutionContext().SecurityContext;
_sc._disableFlow = flags;
_thread = currentThread;
}
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
[SecurityCritical]
internal void Setup()
{
useEC = true;
Thread currentThread = Thread.CurrentThread;
_ec = currentThread.GetMutableExecutionContext();
_ec.isFlowSuppressed = true;
_thread = currentThread;
} public void Dispose()
{
Undo();
} [SecuritySafeCritical]
public void Undo()
{
if (_thread == null)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseAFCMultiple"));
}
if (_thread != Thread.CurrentThread)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotUseAFCOtherThread"));
}
if (useEC)
{
if (Thread.CurrentThread.GetMutableExecutionContext() != _ec)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsyncFlowCtrlCtxMismatch"));
}
ExecutionContext.RestoreFlow();
}
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
else
{
if (!Thread.CurrentThread.GetExecutionContextReader().SecurityContext.IsSame(_sc))
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AsyncFlowCtrlCtxMismatch"));
}
SecurityContext.RestoreFlow();
}
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
_thread = null;
} }

AsyncFlowControl的code比较简单,里面有ExecutionContext和SecurityContext两个上下文,SecurityContext是一个很重要的 与认证权限有关的,这里我们忽略它,我们的核心主要关注ExecutionContext的实现方式和思路,注意Setup方法中【_ec = currentThread.GetMutableExecutionContext();_ec.isFlowSuppressed = true;】,现在我们再来看看ExecutionContext的实现:

public sealed class ExecutionContext : IDisposable, ISerializable
{
#if FEATURE_CAS_POLICY
private HostExecutionContext _hostExecutionContext;
#endif // FEATURE_CAS_POLICY
private SynchronizationContext _syncContext;
private SynchronizationContext _syncContextNoFlow;
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
private SecurityContext _securityContext;
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
#if FEATURE_REMOTING
private LogicalCallContext _logicalCallContext;
private IllogicalCallContext _illogicalCallContext; // this call context follows the physical thread
#endif // #if FEATURE_REMOTING
private Flags _flags;
private Dictionary<IAsyncLocal, object> _localValues;
private List<IAsyncLocal> _localChangeNotifications; public static AsyncFlowControl SuppressFlow()
{
if (IsFlowSuppressed())
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotSupressFlowMultipleTimes"));
}
Contract.EndContractBlock();
AsyncFlowControl afc = new AsyncFlowControl();
afc.Setup();
return afc;
} public static void RestoreFlow()
{
ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
if (!ec.isFlowSuppressed)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotRestoreUnsupressedFlow"));
}
ec.isFlowSuppressed = false;
} public static bool IsFlowSuppressed()
{
return Thread.CurrentThread.GetExecutionContextReader().IsFlowSuppressed;
} public static ExecutionContext Capture()
{
// set up a stack mark for finding the caller
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return ExecutionContext.Capture(ref stackMark, CaptureOptions.None);
}
static internal ExecutionContext Capture(ref StackCrawlMark stackMark, CaptureOptions options)
{
ExecutionContext.Reader ecCurrent = Thread.CurrentThread.GetExecutionContextReader();
// check to see if Flow is suppressed
if (ecCurrent.IsFlowSuppressed)
return null; #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
// capture the security context
SecurityContext secCtxNew = SecurityContext.Capture(ecCurrent, ref stackMark);
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
#if FEATURE_CAS_POLICY
// capture the host execution context
HostExecutionContext hostCtxNew = HostExecutionContextManager.CaptureHostExecutionContext();
#endif // FEATURE_CAS_POLICY
SynchronizationContext syncCtxNew = null; #if FEATURE_REMOTING
LogicalCallContext logCtxNew = null;
#endif if (!ecCurrent.IsNull)
{
// capture the sync context
if ( == (options & CaptureOptions.IgnoreSyncCtx))
syncCtxNew = (ecCurrent.SynchronizationContext == null) ? null : ecCurrent.SynchronizationContext.CreateCopy(); #if FEATURE_REMOTING
// copy over the Logical Call Context
if (ecCurrent.LogicalCallContext.HasInfo)
logCtxNew = ecCurrent.LogicalCallContext.Clone();
#endif // #if FEATURE_REMOTING
} Dictionary<IAsyncLocal, object> localValues = null;
List<IAsyncLocal> localChangeNotifications = null;
if (!ecCurrent.IsNull)
{
localValues = ecCurrent.DangerousGetRawExecutionContext()._localValues;
localChangeNotifications = ecCurrent.DangerousGetRawExecutionContext()._localChangeNotifications;
} //
// If we didn't get anything but defaults, and we're allowed to return the
// dummy default EC, don't bother allocating a new context.
//
if ( != (options & CaptureOptions.OptimizeDefaultCase) &&
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
secCtxNew == null &&
#endif
#if FEATURE_CAS_POLICY
hostCtxNew == null &&
#endif // FEATURE_CAS_POLICY
syncCtxNew == null &&
#if FEATURE_REMOTING
(logCtxNew == null || !logCtxNew.HasInfo) &&
#endif // #if FEATURE_REMOTING
localValues == null &&
localChangeNotifications == null
)
{
return s_dummyDefaultEC;
} //
// Allocate the new context, and fill it in.
//
ExecutionContext ecNew = new ExecutionContext();
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
ecNew.SecurityContext = secCtxNew;
if (ecNew.SecurityContext != null)
ecNew.SecurityContext.ExecutionContext = ecNew;
#endif
#if FEATURE_CAS_POLICY
ecNew._hostExecutionContext = hostCtxNew;
#endif // FEATURE_CAS_POLICY
ecNew._syncContext = syncCtxNew;
#if FEATURE_REMOTING
ecNew.LogicalCallContext = logCtxNew;
#endif // #if FEATURE_REMOTING
ecNew._localValues = localValues;
ecNew._localChangeNotifications = localChangeNotifications;
ecNew.isNewCapture = true;
return ecNew;
} public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state)
{
if (executionContext == null)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullContext"));
if (!executionContext.isNewCapture)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotNewCaptureContext")); Run(executionContext, callback, state, false);
} internal static void Run(ExecutionContext executionContext, ContextCallback callback, Object state, bool preserveSyncCtx)
{
RunInternal(executionContext, callback, state, preserveSyncCtx);
}
internal static void RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, bool preserveSyncCtx)
{
Contract.Assert(executionContext != null);
if (executionContext.IsPreAllocatedDefault)
{
Contract.Assert(executionContext.IsDefaultFTContext(preserveSyncCtx));
}
else
{
Contract.Assert(executionContext.isNewCapture);
executionContext.isNewCapture = false;
} Thread currentThread = Thread.CurrentThread;
ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher); RuntimeHelpers.PrepareConstrainedRegions();
try
{
ExecutionContext.Reader ec = currentThread.GetExecutionContextReader();
if ( (ec.IsNull || ec.IsDefaultFTContext(preserveSyncCtx)) &&
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
SecurityContext.CurrentlyInDefaultFTSecurityContext(ec) &&
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
executionContext.IsDefaultFTContext(preserveSyncCtx) &&
ec.HasSameLocalValues(executionContext)
)
{
// Neither context is interesting, so we don't need to set the context.
// We do need to reset any changes made by the user's callback,
// so here we establish a "copy-on-write scope". Any changes will
// result in a copy of the context being made, preserving the original
// context.
EstablishCopyOnWriteScope(currentThread, true, ref ecsw);
}
else
{
if (executionContext.IsPreAllocatedDefault)
executionContext = new ExecutionContext();
ecsw = SetExecutionContext(executionContext, preserveSyncCtx);
} //
// Call the user's callback
//
callback(state);
}
finally
{
ecsw.Undo();
}
} public ExecutionContext CreateCopy()
{
if (!isNewCapture)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotCopyUsedContext"));
}
ExecutionContext ec = new ExecutionContext();
ec.isNewCapture = true;
ec._syncContext = _syncContext == null ? null : _syncContext.CreateCopy();
ec._localValues = _localValues;
ec._localChangeNotifications = _localChangeNotifications;
#if FEATURE_CAS_POLICY
// capture the host execution context
ec._hostExecutionContext = _hostExecutionContext == null ? null : _hostExecutionContext.CreateCopy();
#endif // FEATURE_CAS_POLICY
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
if (_securityContext != null)
{
ec._securityContext = _securityContext.CreateCopy();
ec._securityContext.ExecutionContext = ec;
}
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK #if FEATURE_REMOTING
if (this._logicalCallContext != null)
ec.LogicalCallContext = (LogicalCallContext)this.LogicalCallContext.Clone(); Contract.Assert(this._illogicalCallContext == null);
#endif // #if FEATURE_REMOTING return ec;
} internal static ExecutionContextSwitcher SetExecutionContext(ExecutionContext executionContext, bool preserveSyncCtx)
{
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK Contract.Assert(executionContext != null);
Contract.Assert(executionContext != s_dummyDefaultEC); // Set up the switcher object to return;
ExecutionContextSwitcher ecsw = new ExecutionContextSwitcher(); Thread currentThread = Thread.CurrentThread;
ExecutionContext.Reader outerEC = currentThread.GetExecutionContextReader(); ecsw.thread = currentThread;
ecsw.outerEC = outerEC;
ecsw.outerECBelongsToScope = currentThread.ExecutionContextBelongsToCurrentScope; if (preserveSyncCtx)
executionContext.SynchronizationContext = outerEC.SynchronizationContext;
executionContext.SynchronizationContextNoFlow = outerEC.SynchronizationContextNoFlow; currentThread.SetExecutionContext(executionContext, belongsToCurrentScope: true); RuntimeHelpers.PrepareConstrainedRegions();
try
{
OnAsyncLocalContextChanged(outerEC.DangerousGetRawExecutionContext(), executionContext); #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
//set the security context
SecurityContext sc = executionContext.SecurityContext;
if (sc != null)
{
// non-null SC: needs to be set
SecurityContext.Reader prevSeC = outerEC.SecurityContext;
ecsw.scsw = SecurityContext.SetSecurityContext(sc, prevSeC, false, ref stackMark);
}
else if (!SecurityContext.CurrentlyInDefaultFTSecurityContext(ecsw.outerEC))
{
// null incoming SC, but we're currently not in FT: use static FTSC to set
SecurityContext.Reader prevSeC = outerEC.SecurityContext;
ecsw.scsw = SecurityContext.SetSecurityContext(SecurityContext.FullTrustSecurityContext, prevSeC, false, ref stackMark);
}
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
#if FEATURE_CAS_POLICY
// set the Host Context
HostExecutionContext hostContext = executionContext.HostExecutionContext;
if (hostContext != null)
{
ecsw.hecsw = HostExecutionContextManager.SetHostExecutionContextInternal(hostContext);
}
#endif // FEATURE_CAS_POLICY
}
catch
{
ecsw.UndoNoThrow();
throw;
}
return ecsw;
}
}

从ExecutionContext的成员变量来看,ExecutionContext包含很多上下文的,HostExecutionContext,SynchronizationContext,SecurityContext,LogicalCallContext和IllogicalCallContext。

SuppressFlow实例化一个AsyncFlowControl然后调用SetUP方法【_ec = currentThread.GetMutableExecutionContext();_ec.isFlowSuppressed = true;】,RestoreFlow获取执行上下文【 ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext()】,这2个方法的执行上细文是相同的。

接下来我们来看看Capture方法,首先获取ExecutionContext.Reader【线程上下文的一个包装】

internal ExecutionContext.Reader GetExecutionContextReader()
{
return new ExecutionContext.Reader(m_ExecutionContext);
}

然后检查IsFlowSuppressed,最后依次捕获上下文

1.  SecurityContext secCtxNew = SecurityContext.Capture(ecCurrent, ref stackMark)

2. HostExecutionContext hostCtxNew = HostExecutionContextManager.CaptureHostExecutionContext()

3.  syncCtxNew = (ecCurrent.SynchronizationContext == null) ? null : ecCurrent.SynchronizationContext.CreateCopy()

4.  logCtxNew = ecCurrent.LogicalCallContext.Clone()

5. localValues = ecCurrent.DangerousGetRawExecutionContext()._localValues;localChangeNotifications = ecCurrent.DangerousGetRawExecutionContext()._localChangeNotifications;

这个我们捕获这些上下文,那么后面的CreateCopy其实也需要拷贝这些上下文的。

这里的Run方法,使用上比较好理解【调用ContextCallback传入特定线程的上下文】,但是代码层面就不是那么好理解了,里面还借助了ExecutionContextSwitcher对象,但是和兴实现是ecsw = SetExecutionContext(executionContext, preserveSyncCtx)【还原线程上下文】

如:

ExecutionContext ec = new ExecutionContext();
ec.isNewCapture = true;
ec._syncContext = _syncContext == null ? null : _syncContext.CreateCopy();
ec._localValues = _localValues;
ec._localChangeNotifications = _localChangeNotifications;
ec._hostExecutionContext = _hostExecutionContext == null ? null : _hostExecutionContext.CreateCopy();
if (_securityContext != null)
{
ec._securityContext = _securityContext.CreateCopy();
ec._securityContext.ExecutionContext = ec;
}
if (this._logicalCallContext != null)
ec.LogicalCallContext = (LogicalCallContext)this.LogicalCallContext.Clone();

所以从使用ExecutionContext 的角度来讲,还是很好理解的,先用Capture方法捕获线程上这些上下文保存到ExecutionContext 实例里面,最后在调用Run方法时需要还原线程的这些上下文【来源先前保存到ExecutionContext 实例】。

C# ExecutionContext 实现的更多相关文章

  1. ExecutionContext(执行上下文)综述

    >>返回<C# 并发编程> 1. 简介 2. 同步异步对比 3. 上下文的捕获和恢复 4. Flowing ExecutionContext vs Using Synchron ...

  2. 理解C#中的ExecutionContext vs SynchronizationContext

    原文:https://devblogs.microsoft.com/pfxteam/executioncontext-vs-synchronizationcontext/ 作者:Stephen 翻译: ...

  3. 【C# TAP 异步编程】四、SynchronizationContext 同步上下文|ExecutionContext

    一.同步上下文(SynchronizationContext)概述 由来 多线程程序在.net框架出现之前就已经存在了.这些程序通常需要一个线程将一个工作单元传递给另一个线程.Windows程序以消息 ...

  4. 执行上下文与同步上下文 | ExecutionContext 和 SynchronizationContext

    原文连接:执行上下文与同步上下文 - .NET 并行编程 (microsoft.com) 执行上下文与同步上下文 斯蒂芬 6月15日, 2012 最近,我被问了几次关于 ExecutionContex ...

  5. C#与C++的发展历程第三 - C#5.0异步编程巅峰

    系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...

  6. .NET基础拾遗(5)多线程开发基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  7. 查看w3wp进程占用的内存及.NET内存泄露,死锁分析

    一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...

  8. 浅谈Slick(2)- Slick101:第一个动手尝试的项目

    看完Slick官方网站上关于Slick3.1.1技术文档后决定开始动手建一个项目来尝试一下Slick功能的具体使用方法.我把这个过程中的一些了解和想法记录下来和大家一起分享.首先我用IntelliJ- ...

  9. 探索c#之Async、Await剖析

    阅读目录: 基本介绍 基本原理剖析 内部实现剖析 重点注意的地方 总结 基本介绍 Async.Await是net4.x新增的异步编程方式,其目的是为了简化异步程序编写,和之前APM方式简单对比如下. ...

随机推荐

  1. PHP把采集抓取网页的html中的的&nbsp;去掉或者分割成数组

    日期:2017/11/6 操作系统:windows 今天抓取网页的时候出现 无法替换,经过多次测试,找到了办法;(注意是从网页上抓取到的) 分割 explode("  ",HTML ...

  2. 初窥Java之三

    一.基本数据类型之浮点型 每个数据它自身都有一个默认的类型,如果直接打印小数,默认类型就为double类型: float和double表示小数的精度不是特别的高,如果对于精确度要求非常的高,我们 都使 ...

  3. 2018 icpc 青岛网络赛 J.Press the Button

    Press the Button Time Limit: 1 Second      Memory Limit: 131072 KB BaoBao and DreamGrid are playing ...

  4. hdu3944

    hdu3944题目中给出的杨辉三角形的形状带有误导目的,应该转化成对称的形状再去思考这个问题分两种情况第一个是在左区从目标位置向左上方走一直走到边界,然后再向右上方一直走到起点n-k个1加上C(n-k ...

  5. SpringMvc接口中转设计(策略+模板方法)

    一.前言 最近带着两个兄弟做支付宝小程序后端相关的开发,小程序首页涉及到很多查询的服务.小程序后端服务在我司属于互联网域,相关的查询服务已经在核心域存在了,查询这块所要做的工作就是做接口中转.参考了微 ...

  6. mysql数据库操作语句整合

    查看版本:select version();显示当前时间:select now(); 注意:在语句结尾要使用分号; 远程连接 一般在公司开发中,可能会将数据库统一搭建在一台服务器上,所有开发人员共用一 ...

  7. SpringMVC(十六) 处理模型数据之SessionAttributes

    @SessionAttributes原理 默认情况下Spring MVC将模型中的数据存储到request域中.当一个请求结束后,数据就失效了.如果要跨页面使用.那么需要使用到session.而@Se ...

  8. PHP 操作 MySQL 执行数据库事务

    <?php $mysqli=new mysqli();//实例化mysqli $mysqli->connect('localhost','root','admin','test'); if ...

  9. iOS12系统应用发送普通邮件构建邮件

    iOS12系统应用发送普通邮件构建邮件 当确定设备支持邮件发送功能后,开发者就可以实现该功能.根据是否包含附件,邮件可以分为普通邮件和附件邮件两种.本节首先讲解如何发送普通邮件.实现过程如下: 1.构 ...

  10. 潭州课堂25班:Ph201805201 django框架 第二课 url,,include,kwargs,name的使用 (课堂笔记)

    url 路由配置 这里的 name 由用户输入,得到参数 /<>/是获取用户输入值 这里的 name 默认接收的是 str 如果要接收 int 时: 当输入参数非数字时提示错误 最常用是 ...