网上关于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. ELK 环境搭建1-Elasticsearch

    一.安装前准备 1.节点 192.168.30.41 192.168.30.42 192.168.30.43 2.操作系统: Centos7.5 3.安装包 a.java8: jdk-8u181-li ...

  2. BZOJ2553 [BeiJing2011]禁忌 AC自动机 矩阵

    原文链接http://www.cnblogs.com/zhouzhendong/p/8196279.html 题目传送门 - BZOJ2553 题意概括 引用一下lych大佬的: 在字母只有前alph ...

  3. ML激活函数使用法则

    sigmoid .tanh .ReLu tanh 函数或者双曲正切函数是总体上都优于 sigmoid 函数的激活函数. 基本已经不用 sigmoid 激活函数了,tanh 函数在所有场合都优于 sig ...

  4. 20165235 2017-2018-2《Java程序设计》课程总结

    20165235 2017-2018-2<Java程序设计>课程总结 每周作业链接汇总 预备作业一 预备作业二 预备作业三 第一周学习总结 第二周学习总结 第三周学习总结 第四周学习总结 ...

  5. day7 [id],[is],编码

    老师的笔记: 字典:dic = {'name':'alex'} 1,增 dic['k'] = 'v' 有键值对,则覆盖 setdefault 有键值对,不添加 dic.setdefault('k1', ...

  6. react 环境搭建

    1:需要给系统装一个node  https://nodejs.org/zh-cn/ 2:然后需要到cmd安装一个淘宝镜像 (在cmd上面执行): npm install -g cnpm --regis ...

  7. 使用 PySide2 开发 Maya 插件系列 总览

    使用 PySide2 开发 Maya 插件系列 总览 使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件 ...

  8. SVM:随机产生100个点,建立模型,找出超平面方程——Jaosn niu

    import numpy as np import pylab as pl from sklearn import svm # we create 40 separable points #np.ra ...

  9. 【python】常用第三方模块

    No1: [Pillow]图像处理标准库 缩放 from PIL import Image # 打开一个jpg图像文件,注意是当前路径: im = Image.open('test.jpg') # 获 ...

  10. 上海市2019年公务员录用考试笔试合格人员笔试成绩(B类)

    考试类别:B类 注册编号 总成绩 注册编号 总成绩 注册编号 总成绩 注册编号 总成绩 5101919 154.7 5113380 156.5 5126791 133.5 5146138 126.2 ...