C# ExecutionContext 实现

来源:互联网 发布:嵌入式转人工智能领域 编辑:程序博客网 时间:2024/06/11 06:53

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

 名称说明System_CAPS_pubmethodSystem_CAPS_staticCapture()

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

System_CAPS_pubmethodCreateCopy()

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

System_CAPS_pubmethodDispose()

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

System_CAPS_pubmethodEquals(Object)

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

System_CAPS_pubmethodGetHashCode()

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

System_CAPS_pubmethodGetObjectData(SerializationInfo, StreamingContext)

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

System_CAPS_pubmethodGetType()

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

System_CAPS_pubmethodSystem_CAPS_staticIsFlowSuppressed()

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

System_CAPS_pubmethodSystem_CAPS_staticRestoreFlow()

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

System_CAPS_pubmethodSystem_CAPS_staticRun(ExecutionContext, ContextCallback, Object)

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

System_CAPS_pubmethodSystem_CAPS_staticSuppressFlow()

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

System_CAPS_pubmethodToString()

返回表示当前对象的字符串。(继承自 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 (0 == (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 (0 != (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 实例】

原创粉丝点击