网上关于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. Hbase的写入负载均衡

    在写Hbase的时候,会担心数据分布在各个region上不均匀(与预分区无关): 这个时候可能想到的方式:hash.加盐等(当然是可以的,但是读取的时候咋办呢? 哪天写一个这样的文章) 本文采用新方式 ...

  2. k8s 相关命令

    kompose convert -f docker-compose-pro.yml k8s数据卷挂载: https://blog.csdn.net/wlhdo71920145/article/deta ...

  3. vue中使用axios最详细教程

    前提条件:vue-cli 项目 安装: npm npm 在main.js导入: // 引入axios,并加到原型链中 import axios from 'axios'; Vue.prototype. ...

  4. HtmlTestRunner

    1.一般生成报告时,会使用时间来作为报告名称的一部分,引入time这个第三方,使用以下方式格式化当前时间 下面运行最终结果:2019-03-29-14_29_18------>年-月-日-时-分 ...

  5. jenkins创建svn项目自动部署

    Exec command ; cd /home/zhxjdk18/server/jenkins_project/owgd_site/admin; rm -rf * ; source .bashrc ; ...

  6. php 图形用户界面GUI 开发

    php 图形用户界面GUI 开发 一.下载指定系统扩展 1 2 http://pecl.php.net/package/ui http://pecl.php.net/package/ui/2.0.0/ ...

  7. 搭建JMETER+ANT自动化接口测试环境步骤(一)

    一.环境准备: 1.JDK    下载            地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html ...

  8. Django分页(二)

    Django分页(二) 要求 .设定每页显示数据条数 # # .用户输入页码(第一页.第二页...) # # .设定显示多少页号 # # .获取当前数据总条数 # # .根据设定显示多少页号和数据总条 ...

  9. DNS信息收集工具dig使用

    Dig是域信息搜索器的简称(Domain Information Groper),使用dig命令可以执行查询域名相关的任务 常见域名记录: A(主机记录 把一个域名解析成IP地址) C name(别名 ...

  10. Docker 搭建 Tomcat + Mysql

    Docker 搭建 Tomcat + Mysql 准备 虚拟机 虚拟机安装Docker 在纯净的Centos镜像上搭建 Centos镜像准备 虚拟机上拉取 Centos 镜像: docker pull ...