ExecutionContext类详解

一、ExecutionContext类的定义

public sealed class ExecutionContext : IDisposable, ISerializable

该类是Thread中的一个内部类

二、ExectutionContext中的字段

//默认的执行上下文
internal static readonly ExecutionContext Default = new ExecutionContext();
private static volatile ExecutionContext? s_defaultFlowSuppressed;
private readonly IAsyncLocalValueMap? m_localValues;
private readonly IAsyncLocal[]? m_localChangeNotifications;
//是否禁止执行上文的传递
private readonly bool m_isFlowSuppressed;
//是否是默认的上下文
private readonly bool m_isDefault;

三、构造方法

//该构造函数用于创建一个默认的上下文
private ExecutionContext(){
	m_isDefault = true;
}
//有参构造函数
private ExecutionContext(IAsyncLocalValueMap localValues, IAsyncLocal[]? localChangeNotifications,bool isFlowSuppressed){
	m_localValues = localValues;
	m_localChangeNotifications = localChangeNotifications;
	m_isFlowSuppressed = isFlowSuppressed;
}

四、常用的方法

4.1 Run方法与RunInternal方法

这两个方法是极度热门的两个函数,每个await以及ThreadPool的execution都会执行该方法

public static void Run(ExecutionContext executionContext, ContextCallback callback, object? state) {
	if (executionContext == null){
		//如果执行上下文为空则抛出异常
 		ThrowNullContext();
	} 
	RunInternal(executionContext, callback, state);
}
 
internal static void RunInternal(ExecutionContext? executionContext, ContextCallback callback, object? state) {
    // Note: Manual enregistering may be addressed by "Exception Handling Write Through Optimization"
    // Enregister previousExecutionCtx0 so they can be used in registers without EH forcing them to stack
    Thread currentThread = Thread.CurrentThread;
    //获取当前线程的上下文
    ExecutionContext? previousExecutionCtx0 = currentThread._executionContext;
    if (previousExecutionCtx0 != null && previousExecutionCtx0.m_isDefault) {
        //如果当前上下文为默认上下文则置空
        previousExecutionCtx0 = null;
    }

    ExecutionContext? previousExecutionCtx = previousExecutionCtx0;
    //获取当前线程的同步上下文
    SynchronizationContext? previousSyncCtx = currentThread._synchronizationContext;
    if (executionContext != null && executionContext.m_isDefault) {
        //如果传入的上下文为默认上下文,则置空
        executionContext = null;
    }
	
    if (previousExecutionCtx != executionContext) {
    	//当前线程中的上下文与传入的上文不同则切换上下文
        RestoreChangedContextToThread(currentThread, executionContext, previousExecutionCtx);
    }

    ExceptionDispatchInfo? edi = null;
    //上下文切换完成后开始运行
    try {
    	//调用startHelper中定义的runWorker
        callback.Invoke(state);
    } catch (Exception ex) {
    	//如果调用callback时出错则捕获该异常,等到恢复上下文后在抛出异常
        edi = ExceptionDispatchInfo.Capture(ex);
    }

    // The common case is that these have not changed, so avoid the cost of a write barrier if not needed.
    if (currentThread._synchronizationContext != previousSyncCtx) {
        //如果当前线程的同步上下文发生了变化,则切换为原来的同步上下文
        currentThread._synchronizationContext = previousSyncCtx;
    }

    ExecutionContext? currentExecutionCtx = currentThread._executionContext;
    if (currentExecutionCtx != previousExecutionCtx) {
    	//如果当前线程的执行上下文发生了变化,则切换为原来的执行上下文
        RestoreChangedContextToThread(currentThread, previousExecutionCtx, currentExecutionCtx);
    }

    //如果callback中抛出了异常,那么这里重新抛出
    edi?.Throw();
}

4.2、GetObjectData方法

该方法是序列化接口中定义的方法的实现

public void GetObjectData(SerializationInfo info, StreamingContext context){
    throw new PlatformNotSupportedException();
}

4.3、Capture方法

获取当前线程使用的执行上下文

public static ExecutionContext? Capture() {
     ExecutionContext? executionContext = Thread.CurrentThread._executionContext;
     if (executionContext == null){
     	//如果当前线程使用的执行上下文为空则使用默认的执行上下文
        executionContext = Default;
     }else if (executionContext.m_isFlowSuppressed){
     			//如果当前执行上下文不为空,但是不允许上下文传递,则返回null
                executionContext = null;
    }
 	return executionContext;
}

4.4、获取线程上下文

//获取当前线程中的执行上下文
internal static ExecutionContext? CaptureForRestore(){ 
	return Thread.CurrentThread._executionContext;
}
//返回一个新建的上下文对象
private ExecutionContext? ShallowClone(bool isFlowSuppressed){
	Debug.Assert(isFlowSuppressed != m_isFlowSuppressed);
	if (m_localValues == null || AsyncLocalValueMap.IsEmpty(m_localValues)){
#pragma warning disable CA1825 // Avoid unnecessary zero-length array allocations
                return isFlowSuppressed ?
                    (s_defaultFlowSuppressed ??= new ExecutionContext(AsyncLocalValueMap.Empty, new IAsyncLocal[0], isFlowSuppressed: true)) :
                    null; // implies the default context
#pragma warning restore CA1825
	}
	return new ExecutionContext(m_localValues, m_localChangeNotifications, isFlowSuppressed);
}

4.5、控制线程上下文的传递

public static AsyncFlowControl SuppressFlow(){
	Thread currentThread = Thread.CurrentThread;
	ExecutionContext? executionContext = currentThread._executionContext ?? Default;
    if (executionContext.m_isFlowSuppressed){
    	throw new InvalidOperationException(SR.InvalidOperation_CannotSupressFlowMultipleTimes);
     }
	 executionContext = executionContext.ShallowClone(isFlowSuppressed: true);
     AsyncFlowControl asyncFlowControl = default;
     currentThread._executionContext = executionContext;
     asyncFlowControl.Initialize(currentThread);
     return asyncFlowControl;
}
//恢复上下文的传递
public static void RestoreFlow(){
	//获取当前线程
	Thread currentThread = Thread.CurrentThread;
	//获取当前线程的执行上下文
 	ExecutionContext? executionContext = currentThread._executionContext;
    if (executionContext == null || !executionContext.m_isFlowSuppressed){
    	//如果执行上下文为null或者允许执行上下文传递则抛出异常(原本就没有禁止,那么就不需要回复)
        throw new InvalidOperationException(SR.InvalidOperation_CannotRestoreUnsupressedFlow);
    }
    //程序运行到这里说执行上下文不为null,并且原来是不允许上下文传递的,则现在会上下文的传递
 	currentThread._executionContext = executionContext.ShallowClone(isFlowSuppressed: false);
}
//判断执行上下文是否允许传递,如果上下文为null表示允许传递
public static bool IsFlowSuppressed(){
	//获取当前线程的执行上下文
	ExecutionContext? executionContext = Thread.CurrentThread._executionContext;
    return executionContext != null && executionContext.m_isFlowSuppressed;
}
//是否存在改变通知
internal bool HasChangeNotifications => m_localChangeNotifications != null;
 //是否是默认上下文
internal bool IsDefault => m_isDefault;

4.6、切换线程上下文

public static void Restore(ExecutionContext executionContext){
    if (executionContext == null){
        ThrowNullContext();
    }
     RestoreInternal(executionContext);
}
 
internal static void RestoreInternal(ExecutionContext? executionContext){
	Thread currentThread = Thread.CurrentThread;
	//获取当前线程的上下文
	ExecutionContext? currentExecutionCtx = currentThread._executionContext;
    if (currentExecutionCtx != null && currentExecutionCtx.m_isDefault){
        //如果当前线程中的上下文为默认的上下文,则置空
    	currentExecutionCtx = null;
    }
 	
    if (executionContext != null && executionContext.m_isDefault){
         //如果传入的上下文为默认的上下文,则置空
         executionContext = null;
    }
 
    if (currentExecutionCtx != executionContext){
    	//如果当前上下文与传入的上下文不是同一个(说明需要切换上下文),则切换当前线程的上下文
    	RestoreChangedContextToThread(currentThread, executionContext, currentExecutionCtx);
    }
}
internal static void RestoreChangedContextToThread(Thread currentThread, ExecutionContext? contextToRestore, ExecutionContext? currentContext) {
    Debug.Assert(currentThread == Thread.CurrentThread);
    Debug.Assert(contextToRestore != currentContext);

    // Restore changed ExecutionContext back to previous
    //设置当前线程的上下文
    currentThread._executionContext = contextToRestore;
    if ((currentContext != null && currentContext.HasChangeNotifications) ||
        (contextToRestore != null && contextToRestore.HasChangeNotifications)) {
        //当前线程的上下文切换后,如果切换之前的上下文中或者现在的上下文中存在上下文切换通知的则
        //触发上下文切换通知
        OnValuesChanged(currentContext, contextToRestore);
    }
}
//如果值发生了变化,则调用其变化通知
internal static void OnValuesChanged(ExecutionContext? previousExecutionCtx, ExecutionContext? nextExecutionCtx) {
    Debug.Assert(previousExecutionCtx != nextExecutionCtx);

    // Collect Change Notifications
    IAsyncLocal[]? previousChangeNotifications = previousExecutionCtx?.m_localChangeNotifications;
    IAsyncLocal[]? nextChangeNotifications = nextExecutionCtx?.m_localChangeNotifications;

    // At least one side must have notifications
    Debug.Assert(previousChangeNotifications != null || nextChangeNotifications != null);

    // Fire Change Notifications
    try {
        if (previousChangeNotifications != null && nextChangeNotifications != null) {
        	//previous和next中都存在变化通知
            // Notifications can't exist without values
            Debug.Assert(previousExecutionCtx!.m_localValues != null);
            Debug.Assert(nextExecutionCtx!.m_localValues != null);
            // Both contexts have change notifications, check previousExecutionCtx first
            foreach (IAsyncLocal local in previousChangeNotifications) {
            	//依次遍历调用previous中的变化通知
                previousExecutionCtx.m_localValues.TryGetValue(local, out object? previousValue);
                nextExecutionCtx.m_localValues.TryGetValue(local, out object? currentValue);
                if (previousValue != currentValue) {
                	//如果当前key对应的value发生了变化,就开始触发对应通知
                    local.OnValueChanged(previousValue, currentValue, contextChanged: true);
                }
            }

            if (nextChangeNotifications != previousChangeNotifications) {
                foreach (IAsyncLocal local in nextChangeNotifications) {
                    //依次遍历next中的key
                    if (!previousExecutionCtx.m_localValues.TryGetValue(local, out object? previousValue)) {
                    	//如果当前key不存在与prevoius中,说明该事件没有遍历过,如果值发生改变,则触发改变通知
                        nextExecutionCtx.m_localValues.TryGetValue(local, out object? currentValue);
                        if (previousValue != currentValue) {
                            local.OnValueChanged(previousValue, currentValue, contextChanged: true);
                        }
                    }
                }
            }
        } else if (previousChangeNotifications != null) {
        	//程序运行到这里说明previous和next中存在一个不为null,一个为null
            // 这里属于previous不为null,next为null
            Debug.Assert(previousExecutionCtx!.m_localValues != null);
            // No current values, so just check previous against null
            foreach (IAsyncLocal local in previousChangeNotifications) {
                previousExecutionCtx.m_localValues.TryGetValue(local, out object? previousValue);
                if (previousValue != null) {
                	//OnValueChanged是IAsyncLocal接口中声明的方法
                    local.OnValueChanged(previousValue, null, contextChanged: true);
                }
            }
        } else {
            /程序运行到这里说明previous和next中存在一个不为null,一个为null
            // 这里属于previous为null,next不为null
            Debug.Assert(nextExecutionCtx!.m_localValues != null);
            // No previous values, so just check current against null
            foreach (IAsyncLocal local in nextChangeNotifications!) {
                nextExecutionCtx.m_localValues.TryGetValue(local, out object? currentValue);
                if (currentValue != null) {
                    local.OnValueChanged(null, currentValue, contextChanged: true);
                }
            }
        }
    } catch (Exception ex) {
        Environment.FailFast(SR.ExecutionContext_ExceptionInAsyncLocalNotification, ex);
    }
}

4.7、ThreadPool调用的方法

internal static void RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, object state) {
    Debug.Assert(threadPoolThread == Thread.CurrentThread);
    //确保所有内容都是默认的
    CheckThreadPoolAndContextsAreDefault();
   
    if (executionContext != null && !executionContext.m_isDefault) {
        //如果有需要则切换当前上下文
        RestoreChangedContextToThread(threadPoolThread, contextToRestore: executionContext, currentContext: null);
    }
    ExceptionDispatchInfo? edi = null;
    try {
    	//调用委托
        callback.Invoke(state);
    } catch (Exception ex) {
        edi = ExceptionDispatchInfo.Capture(ex);
    }

    //执行完成后,恢复线程池线程为默认状态
    Thread currentThread = threadPoolThread;
    ExecutionContext? currentExecutionCtx = currentThread._executionContext;
    currentThread._synchronizationContext = null;
    if (currentExecutionCtx != null) {
        RestoreChangedContextToThread(currentThread, contextToRestore: null, currentExecutionCtx);
    }
    edi?.Throw();
}

internal static void RunForThreadPoolUnsafe<TState>(ExecutionContext executionContext, Action<TState> callback, in TState state) {
      //确保所有内容都是默认的
    CheckThreadPoolAndContextsAreDefault();
    //确保传入的上下文不是默认的上下文
    Debug.Assert(executionContext != null && !executionContext.m_isDefault, "ExecutionContext argument is Default.");
    //程序运行到这里说明传入的上下文不是默认的,因此这里需要切换上下文
    Thread.CurrentThread._executionContext = executionContext;
    if (executionContext.HasChangeNotifications) {
        OnValuesChanged(previousExecutionCtx: null, executionContext);
    }
    //调用委托
    callback.Invoke(state);
    //这里不再需要重置线程上下文与通知本地数据中有值发生改变,一切由ThreadPoolWorkQueue.Dispatch完成
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值