命名空间:System.Runtime.Remoting.Messaging

类型完全限定名称:System.Runtime.Remoting.Messaging.CallContext

官方介绍:https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.remoting.messaging.callcontext?redirectedfrom=MSDN&view=netframework-4.8

用途:

  用于提供与执行代码路径一起传送的属性集,直白讲就是:提供线程(多线程/单线程)代码执行路径中数据传递的能力。

方法 描述 是否可用于多线程环境
SetData 存储给定的对象并将其与指定名称关联。
GetData 从System.Runtime.Remoting.Messaging.CallContext中检索具有指定名称的对象
LogicalSetData 将给定的对象存储在逻辑调用上下文,并将其与指定名称关联。
LogicalGetData  从逻辑调用上下文中检索具有指定名称的对象。
FreeNamedDataSlot 清空具有指定名称的数据槽。
HostContext  获取或设置与当前线程相关联的主机上下文。在Web环境下等于System.Web.HttpContext.Current

为了更加明确的认识这些方法的作用以及作用我们通过以下代码来了解:

首先定义一个类:

public class User
{
  public string Id { get; set; }

  public string Name { get; set; }
}

一、单线/多线程环境,测试GetData、SetData、FreeNamedDataSlot

下边的输出分别对应1、2、3的输出

根据上述测试结果我们基本可以得出以下结论:

1、GetData、SetData只能用于单线程环境,如果发生了线程切换,存储的数据也会随之丢失

2、可以用于同一线程中的不同地方,传递数据

一、单线/多线程环境,测试LogicalSetData、LogicalGetData、FreeNamedDataSlot

通过上述测试可得出结论:

a、FreeNamedDataSlot只能清除当前线程的数据槽,不能清除子线程的数据槽;

b、LogicalSetData、LogicalGetData可用于在多线程环境下传递数据;

c、FreeNamedDataSlot清除当前线程,之前已经运行子任务,不受影响

通过与上一测试对比我们可以得出结论:

a、FreeNamedDataSlot只能清除当前线程的数据槽

b、LogicalSetData只是存储当前线程以及子线程的数据槽

c、LogicalGetData获取的是当前线程或父线程的数据槽对象,拿到的时对象的引用

d、子线程中使用LogicalSetData改变数据槽的值,不能印象父线程的数据槽,及时他们的key时一个

现在清楚了它的功能,这样我们就可以来思考它的使用场景。

1、可以解耦代码,以前我们向下传递数据是通过参数变量的形式,方法嵌套,我么就需要额外的参数一层一层传递。如果我们Get了CallContext技能,就可以对代码进行解耦;

2、工作单元(UOW),像XPO的工作单元以及ABP的工作单元,都是通过CallContext来实现的,ABP详见IUnitOfWorkManager.Current->ICurrentUnitOfWorkProvider.Current->CallContextCurrentUnitOfWorkProvider.Current

3、 System.Web.HttpContext.Current我们常用来获取当前请求上下文,使用的是System.Runtime.Remoting.Messaging.CallContext.HostContext

System.Runtime.Remoting.Messaging.CallContext.HostContext get访问器和set访问器实现和GetData和SetData的实现方式一致

在.NET Core中使用AsyncLocal代替CallContext,实现的是CallContext.LogicalGetData 和CallContext.SetLogicalCallContext

此处需要重点说下ILogicalThreadAffinative,其作用是:将一个对象,可以将外部传播标记 System.AppDomain 中 System.Runtime.Remoting.Messaging.LogicalCallContext。

如果需要存在在执行上下文中的对象继承了ILogicalThreadAffinative接口,使用LogicalSetData/LogicalGetData和SetData/GetData作用是一样的。请看以下源码截图:

     [SecurityCritical]
public static void SetData(string name, object data)
{
if (data is ILogicalThreadAffinative)
{
LogicalSetData(name, data);
}
else
{
ExecutionContext mutableExecutionContext = Thread.CurrentThread.GetMutableExecutionContext();
mutableExecutionContext.LogicalCallContext.FreeNamedDataSlot(name);
mutableExecutionContext.IllogicalCallContext.SetData(name, data);
}
}
        [SecurityCritical]
public static object GetData(string name)
{
object obj2 = LogicalGetData(name);
return ((obj2 != null) ? obj2 : IllogicalGetData(name));
}

我们可以看到,不管你是使用LogicalSetData还是SetData存储的数据,我们使用GetData都是可以取到的。如果SetData的值是继承ILogicalThreadAffinative接口,那不管使用那个都是一样的效果;

实际上在使用System.Web.HttpContext.Current是通过CallContext.HostContext实现的,在看其源码时发现一个很不理解的现象

     public static object HostContext
{
[SecurityCritical]
get
{
ExecutionContext.Reader executionContextReader = Thread.CurrentThread.GetExecutionContextReader();
object hostContext = executionContextReader.IllogicalCallContext.HostContext;
if (hostContext == null)
{
hostContext = executionContextReader.LogicalCallContext.HostContext;//这里又为什么取,不是无用功么
}
return hostContext;
}
[SecurityCritical]
set
{
ExecutionContext mutableExecutionContext = Thread.CurrentThread.GetMutableExecutionContext();
if (value is ILogicalThreadAffinative)
{
mutableExecutionContext.IllogicalCallContext.HostContext = null;
mutableExecutionContext.LogicalCallContext.HostContext = value;
}
else
{
mutableExecutionContext.IllogicalCallContext.HostContext = value;
mutableExecutionContext.LogicalCallContext.HostContext = null;//此处为什么要设置为null
}
}
}

仔细看了下,取决于

ILogicalThreadAffinative,要不要传播,以此减少一次存储。

.NET多线程之调用上下文CallContext的更多相关文章

  1. CallContext线程数据缓存-调用上下文

    一.CallContext 概述 命名空间:System.Runtime.Remoting.Messaging CallContext 用于提供与执行代码路径一起传送的属性集,直白讲就是:提供线程(多 ...

  2. .NET:线程本地存储、调用上下文、逻辑调用上下文

    .NET:线程本地存储.调用上下文.逻辑调用上下文 目录 背景线程本地存储调用上下文逻辑调用上下文备注 背景返回目录 在多线程环境,如果需要将实例的生命周期控制在某个操作的执行期间,该如何设计?经典的 ...

  3. C# 线程本地存储 调用上下文 逻辑调用上下文

    线程本地存储 using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleAppTest ...

  4. 如何在多线程中调用winform窗体控件

    由于 Windows 窗体控件本质上不是线程安全的.因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态.还可能出现其他与线程相关的 bug,包 ...

  5. Delphi 多线程 “尚未调用CoInitialize错误”的解决方法

    在Delphi  多线程中出现“尚未调用CoInitialize错误”的解决方法 解决方法如下: function  TMyThread.ExecTimer: Boolean;begin  Resul ...

  6. HttpContext在多线程异步调用中的使用方案

    1.在线程调用中,有时候会碰到操作文件之类的功能.对于开发人员来说,他们并不知道网站会被部署在服务器的那个角落里面,因此根本无法确定真实的物理路径(当然可以使用配置文件来配置物理路径),他们唯一知道的 ...

  7. 使用Condition实现多线程之间调用(生产消费模式)

    一,object 类的wait(),notify()和notifyAll() Java 线程类也是一个object 类,它的实例都继承自java.lang.Thread 或其子类.wait(),not ...

  8. JavaScript调用上下文(第九天)

    call与apply用法 使用哪个对象去调用相应的方法: var name="window"; var obj={ name:"obj" } function ...

  9. C++多线程中调用python api函数

    错误场景:一直等待全局锁. 解决方法: 一.首先定义一个封装类,主要是保证PyGILState_Ensure, PyGILState_Release配对使用,而且这个类是可以嵌套使用的. #inclu ...

随机推荐

  1. Win10《芒果TV》商店版更新v3.2.0:全新播放体验,跟着爸爸,想去哪就去哪

    喜迎十一月黑五大促,跟着爸爸,想去哪就去哪,<芒果TV>UWP版迅速更新v3.2.0版,全新播放页华丽蜕变,新增互动评论.猜你喜欢.宽窄屏适配.多窗体模式切换. 芒果TV UWP V3.2 ...

  2. GIS基础软件及操作(六)

    原文 GIS基础软件及操作(六) 练习六.空间分析的应用 1.加深对缓冲区分析基本原理.方法的认识:2.熟练掌握距离制图创建缓冲区技术方法.3.掌握利用缓冲区分析方法解决地学空间分析问题的能力. 1. ...

  3. Android零基础入门第26节:layout_gravity和gravity大不同

    原文:Android零基础入门第26节:layout_gravity和gravity大不同 上一期我们一起学习了LinearLayout线性布局的方向.填充模型和权重,本期来一起学习LinearLay ...

  4. oracle解析

    Oracle数据库中的CURSOR分为两种类型:Shared Cursor 和 Session Cursor 1,Shared Cursor Oracle里的第一种类型的Cursor就是Shared ...

  5. Qt5 结构及模块组成?

    作为一个Qt的粉丝,对将于明年发布的Qt5充满了期待.可是想想Qt5将发生的巨大变化,心底又有点不安.Qt5到底会变成什么样呢? 看看近期Qt5的一些大动作: 从 QtCore中移除 QSetting ...

  6. “多团队大规模”开发模式 - 基于SAP HANA平台的多团队产品研发

    应用SAP HANA “官方”开发模式的伙伴们在转到“多团队大规模”开发模式时会遇到各式各样的心理不适应的状况,各种纠结.比如GIT Repository和HANA Repository冲突什么的. ...

  7. Linux历史,安装,分区,版本

    Linux 历史 1970年是 UNIX元年,这一年 Kenneth Lane Thompson 和 Dennis Ritchie 合作编写了UNIX系统. Stallman 发起了GNU 计划,他本 ...

  8. 使用pjax实现类似github无刷新更改页面url

    pjax=pushState+ajax,相信用过github的同学都知道,github部分页面采用了pjax这个项目来实现ajax无刷新加载的同时改变页面url.一起来学习一下这个插件吧. 我们都知道 ...

  9. asp.net core 系列之Response caching 之 Distributed caching(3)

    这篇文章讲解分布式缓存,即 Distributed caching in ASP.NET Core Distributed caching in ASP.NET Core 分布式缓存是可以在多个应用服 ...

  10. 《阿里巴巴Java开发手册》改名《Java开发手册》,涵盖史无前例的三大升级

    2019.06.19 <阿里巴巴Java开发手册>时隔一年,发布更新1.5.0华山版.同时,将更名为<Java开发手册>,涵盖史无前例的三大升级 1)鉴于本手册是社区开发者集体 ...