前一段时间正好要在某个网页程序上开一个多线程调用多个组件的尝试,这些组件是有其他团队开发的(如:印度/俄罗斯),所以修改它们的代码看起来是不太现实的,但是,令人恼火的是他们的代码中大量的用到了AppContext.Current这个对象(实际上是用了HttpContext.Current.Item来存储的),而一旦异步,HttpContext.Current就不复存在,自然就会不停的报出空引用异常,看起来异步是不太现实的了。

  就在无计可施的时候,突然发现有一个叫CallContext的奇怪的类,藏匿在System.Runtime.Remoting.Messaging这个几乎没人用的namespace下面,当然一开始我仅仅是被它的名称所吸引,直译过来不就是调用上下文吗?感觉这个东西能有点作用。于是查阅了msdn,描述如下:

提供与执行代码路径一起传送的属性集。无法继承此类。

  一句废话。。。看备注吧:

CallContext 是类似于方法调用的线程本地存储区的专用集合对象,并提供对每个逻辑执行线程都唯一的数据槽。数据槽不在其他逻辑线程上的调用上下文之间共享。当 CallContext 沿执行代码路径往返传播并且由该路径中的各个对象检查时,可将对象添加到其中。

当对另一个 AppDomain 中的对象进行远程方法调用时,CallContext 类将生成一个与该远程调用一起传播的 LogicalCallContext 实例。只有公开 ILogicalThreadAffinative 接口并存储在CallContext 中的对象被在 LogicalCallContext 中传播到 AppDomain 外部。不支持此接口的对象不在 LogicalCallContext 实例中与远程方法调用一起传输

  似乎有那么点意思,不过逻辑线程的定义似乎有那么点模棱两可,不过,也提到了一个接口ILogicalThreadAffinative,再看看这个接口定义了什么,一看成员定义。。。没有成员。。。一个空接口,汗了一把,还是看看msdn上如何描述的吧:

标记可以在 LogicalCallContext 中传播到 AppDomain 外部的对象。

  强调了在remoting中的作用,再看看备注:

当对另一个 AppDomain 中的对象进行远程方法调用时,当前的 CallContext 类生成一个将与该调用一起传播到远程位置的 LogicalCallContext。只有公开 ILogicalThreadAffinative 接口并存储在 CallContext 中的对象被传播到 AppDomain 外部。不支持此接口的对象不在LogicalCallContext 实例中与远程方法调用一起传输。

  也是强调在remoting中的作用,但是可以想象,基本上是CallContext中用了类似is ILogicalThreadAffinative的方式,来区别对待不同的对象,对于符合这个接口的将被放到LogicalCallContext,而不符合的另外处理。

  从文档角度,似乎已经没有什么进展了,这时候,突然想起来一个以前看过的很有趣的类型ExecutionContext,namespace是System.Threading,看起来就是多线程准备的,不过,msdn上的例子就说了如何控制传递权限对象的问题,并没有说到如何传递普通对象。

  一时想到所谓的LogicalCallContext会不会在ExecutionContext中存在哪?查了一下msdn,看到备注:

ExecutionContext 类为与执行的逻辑线程相关的所有信息提供单个容器。这包括安全上下文、调用上下文和同步上下文。

ExecutionContext 类提供的功能让户代码可以在用户定义的异步点之间捕获和传输此上下文。公共语言运行库确保在托管进程内运行库定义的异步点之间一致地传输 ExecutionContext。

执行上下文是 COM 单元的托管等效项。在应用程序域中,每当传输线程时都必须传输整个执行上下文。在由 Thread..::.Start 方法、大多数线程池操作和通过 Windows 消息泵进行的 Windows 窗体线程封送处理所导致的传输过程中,将会出现这种情况。在不安全的线程池操作(如UnsafeQueueUserWorkItem 方法)中不会出现这种情况,原因是不安全的线程池操作不会传输压缩堆栈。每当压缩堆栈流动时,托管的主体、同步、区域设置和用户上下文也随之流动。ExecutionContext 类提供 Capture 和 CreateCopy 方法以获取执行上下文,并提供 Run 方法以设置当前线程的执行上下文。

与某个线程相关联的 ExecutionContext 无法在另一个线程上进行设置。尝试这样做会导致引发异常。若要将 ExecutionContext 从一个线程传播到另一个线程,请制作 ExecutionContext 的副本。

ExecutionContext 在内部存储与 LogicalCallContext 相关联的所有数据。这使得可以在复制和传输 ExecutionContext 时传播 LogicalCallContext 数据。

  果然,ExecutionContext中有LogicalCallContext的数据,并且很好的说明了,无论是Thread.Start还是用线程池大多数操作,ExecutionContext都会自动将这些数据传递给那些线程(关于ThreadPool.UnsafeQueueUerWorkItem方法相信用的人应该不多),看起来演员们都到齐了,马上可以演出一场多线程的好戏了。

  首先是起着关键作用ExectionContext,也许我们的代码中没必要出现它的身影,但是那仅仅是因为.net类库的方法,为我们很好封装了这个功能,没有它,想在一个线程中把一个对象告诉另一个线程,就只有通过堆了。

  其次,LogicalCallContext,在众多ExecutionContext传播的对象中,很多是我们无法简单的利用的(总不能为了传播一个对象,去定义一个自定义的权限吧),而LogicalCallContext就是自定义对象的最好的载体。

  最后,剩下的问题就是如何读写这个LogicalCallContext的问题了,也就是终于轮到CallContext出场了。看一下CallContext为我们准备了些什么方法:GetData, SetData, LogicalGetData, LogicalSetData, FreeNamedDataSlot, GetHeader, SetHeader以及HostContext属性。

  第一焦点,当然是GetData和SetData这两个方法,做了个简单的测试,发现这两个方法,确实就是通过ILogicalThreadAffinative接口来决定是否要把对象发给新线程的,而删除这个数据的方法就是FreeNamedDataSlot,现在只要为每一个要在多线程中共用的对象加上一个空接口,并且在多线程开始前在主线程中把对象设置进去,然后在其他线程中再取出来就可以把问题搞定了。多线程部分结束后,不要忘记用FreeNamedDataSlot去删除一下。

  不知道大家注意到没有,出了GetData和SetData外,还有一对LogicalGetData和LogicalSetData,这两个是干什么用的哪?是不是和LogicalCallContext的Logical有什么关系哪?

  又把前面的那个简单的实验做了一下,只不过用了LogicalGetData和LogicalSetData这两个方法,结论是无论是否实现ILogicalThreadAffinative接口,对象都可以在新线程内被访问到,也就是说现在可以传播任何数据给新线程,包括.net定义的string,int等基础类型,这个方案已经接近完美了。

  回过头来看看我的任务吧,只需要修改AppContext.Current属性的实现,并且在多线程开始之前和之后做一个小小的处理,其他的组件就可以原封不动的并发的跑在各自的线程上。

  工作上的事情就到此为止了。

  在来说说CallContext.HostContext属性是干什么的,经过简单的测试,发现在Asp.net程序中,这个HostContext里面放的就是HttpContext的实例,ms也够偷懒的。其实ms只要做一个很小的修改,Asp.net的多线程就不用这么麻烦了,只需要HttpContext实现一下ILogicalThreadAffinative接口,无论新开多少个线程,到那边都能访问到HttpContext.Current了,当然ms没有这么做也是有原因的,一旦HttpContext被传播到其他线程,那么asp.net就很难控制HttpContext对象的生命周期,而HttpContext对象又引用这HttpRequest对象,带来的副作用可能要比想象的大得多。

CallContext和多线程的更多相关文章

  1. Asp.Net在多线程环境下的状态存储问题

    在应用开发中,我们经常需要设置一些上下文(Context)信息,这些上下文信息一般基于当前的会话(Session),比如当前登录用户的个人信息:或者基于当前方法调用栈,比如在同一个调用中涉及的多个层次 ...

  2. Abp Uow 设计

    初始化入口 在AbpKernelModule类中,通过UnitOfWorkRegistrar.Initialize(IocManager) 方法去初始化 /// <summary> /// ...

  3. CallContext的LogicalCallContext在多线程环境下面公用变量

    压根名听说过这个类的看这里:如何实现对上下文(Context)数据的统一管理 原来以为CallContext就可以直接在多线程环境下面共享使用的,今天突然想到:Asp.Net环境下面,设置来设置去的, ...

  4. .NET多线程之调用上下文CallContext

    命名空间:System.Runtime.Remoting.Messaging 类型完全限定名称:System.Runtime.Remoting.Messaging.CallContext 官方介绍:h ...

  5. 快速入门系列--CLR--02多线程

    最近,由于基础框架的整体升级,因此需要更新所有相关项目的DLL文件.这个过程存在不小的风险,因此也对发布后的生产服务器进行了密切的监控,结果还是出现了个别应用出现异常的情况,很快的占用了大量的服务器内 ...

  6. 多线程要点--CLR C#学习笔记

    1.windows永远不会调度一个进程,只调度线程. 2.线程和操作系统的关系:CLR(X)--AppDomain--线程池(包含工作者线程和I/O线程) 3.线程的关键组成部分 A.线程执行上下文 ...

  7. ibatis.net 多线程的调试

    ibatis是一个挺不错的半自动orm框架,从java移植到c# 在ibatis中是支持多线程操作的,但是这几天的使用过程中发现就框架本身任然存在一些问题,可能会让你对多线程的使用并不是那么的顺利 在 ...

  8. ASP.NET多线程下使用HttpContext.Current为null解决方案

    多线程或者异步调用中如何访问HttpContext? 前面我还提到在APM模式下的异步完成回调时,访问HttpContext.Current也会返回null,那么此时该怎么办呢? 答案有二种:1. 在 ...

  9. 关于callContext

    coding们肯定有这种需求,在程序中,方法一级级调下去,比如A->b->C->D.... ->Z.在调用过程中,希望在调用函数之间传递一些数据,常见的是将特定的数据从高往低处 ...

随机推荐

  1. webmagic加上了注解支持

    今天有个网友在博客回帖,能不能用注解来写一个爬虫?想了想,因为Javaer总习惯结果有个对象Model(我在自己用的时候也是这样),ResultItems的key-value形式难免会有点麻烦,何不将 ...

  2. 冒泡排序 JAVA版

    冒泡排序 算法思想是每次从数组末端开始比较相邻俩元素,把第i小的冒泡到数组的第i个位置.i从0一直到N-1从而完成排序.当然也可以从数组开始端开始比较相邻两元素,把第i大的冒泡到第N-i个位置.I从0 ...

  3. Hibernate之1-N关联映射

    一.Hibernate之1-N关联映射 1. 哪边是 1 , 哪边是多 ?      须要从业务的角度来说明.比如,Employee 和 Department 之间就是 n-1 的关联关系,Order ...

  4. H2O是开源基于大数据的机器学习库包

    H2O是开源基于大数据的机器学习库包 H2O能够让Hadoop做数学,H2O是基于大数据的 统计分析 机器学习和数学库包,让用户基于核心的数学积木搭建应用块代码,采取类似R语言 Excel或JSON等 ...

  5. JavaFX 简单3D演示样例

    从Java8開始,在JavaFX中便添加了3D部分的内容,包含Camera,Material,Light,Shape3D等基础内容. 当然,JavaFX 3D应该是OpenJFX里眼下正在补充和完好的 ...

  6. Linux从用户层到内核层系列 - GNU系列之glibc介绍

    题记:本系列文章的目的是抛开书本从源代码和使用的角度分析Linux内核和相关源代码,byhankswang和你一起玩转linux开发 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswa ...

  7. OpenCV-Python教程(5、初级滤波内容)

    本篇文章介绍如何用OpenCV-Python来实现初级滤波功能. 提示: 转载请详细注明原作者及出处,谢谢! 本文介绍使用OpenCV-Python实现基本的滤波处理 本文不介绍滤波处理的详细概念,所 ...

  8. php 汉字转拼音 [包含20902个基本汉字+5059生僻字]

    原文:php 汉字转拼音 [包含20902个基本汉字+5059生僻字] 昨天在转换拼音的时候发现个bug,有好多字都无法转换,不过也不能怪他,毕竟人家的库才8k,应该只有常用的.无奈上网找了下,发现一 ...

  9. Android Studio 入门(转)

    本文适用于从Eclipse转AndroidStudio的开发者 最近打算写一个系列的android初级开发教程,预计40篇以上的文章,结合我实际工作中的经验,写一些工作中经常用到的技术,让初学者可以少 ...

  10. JarSearch

    个人做的小工具分享给大家~~. 支持从压缩文件搜索文件,特别是根据部分类文件名在jar里查找文件,比较方便,效率也还不错. 也支持从目录查找 http://pan.baidu.com/s/1feYaM ...