博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ExecutionContext & SynchronizationContext
阅读量:5340 次
发布时间:2019-06-15

本文共 3159 字,大约阅读时间需要 10 分钟。

最近在研究.net4.5中的有关异步编程的新特性,从自己Google Reader 订阅的一些博客中接触到了两个很陌生的单词ExecutionContext和SynchronizationContext,于是仔细研究了一下,记录下来备忘。

什么是ExecutionContext
在许多系统中thread-local storage(TLS)线程本地存储记录了正在运行的当前环境或者上下文的一些信息,而在CLR中ExecutionContext做了类似的事情.在同步的世界中,所有的一切都发生在当前线程内,线程内有关的所有数据对其内所有代码可见,也同时被所有代码所操纵影响.也就是说假设有方法ABC在当前线程内顺序执行,当前线程环境的一切信息对ABC都是可见的,同时ABC又影响着这些当前线程环境.但是在异步的世界情况变了,还假设有方法ABC,这三个方法有可能运行在不同的线程中,ABC三者是相互见不到对方线程信息的,所以需要在每个异步点传递当前线程环境信息到另一个线程中,另一个线程中的方法才能访问该线程中数据信息并且修改这些信息.完成这个任务就需要ExecutionContext记录当前线程环境然后再另一个线程中restore出来. 情况类似于这样:

// 记录当前的环境信息到ec, 这些信息会在委托调用时通过静态的方法Run恢复出来ExecutionContext ec = ExecutionContext.Capture(); ExecutionContext.Run(ec, delegate { … // 在这的代码就能看见ec中的环境信息了。}, null);

在.Net FrameWork中所有处理异步情况的方法都会通过类似的方法Capture/Restore ExecutionContext(不包括unsafe代码),比如Task.Run,ThreadPool.QueueUserWorkItem,Delegate.BeginInvoke,Stream.BeginRead,DispatcherSynchronizationContext.Post 

比如Task.Run,当我们调用Run时,背后所做的事就是ExecutionContext.Capture()捕获当前线程环境,然后在Run中的delegate方法执行的时候把环境还原。

什么是SynchronizationContext

程序员都很热衷与抽象,对硬编码深恶痛绝,分层和抽象会为我们日后维护和扩展系统带来极大的便利,这也就是为什么会有接口,抽象类,和虚方法。而SynchronizationContext也是一种抽象。打个比方,当我们编写WinForm程序时,为避免后台处理海量数据带来的UI界面假死状态,通常会重开线程或者将这些工作放入线程池等,任务完成之后把处理的结果封送返回给UI线程时,通常会用Control.BeginInvoke方法。但是这种情况如果发生在WPF和Silverlight程序中呢,封送处理又得用Dispatcher.BeginInvoke或者InvokeAsync.ASP.Net又是另一种情况。于是我们使用了不同了方法完成了相同的动作,那么对于不同的UI框架我们怎么处理这些相同事件呢?于是抽象的想法来了,这就是SynchronizationContext。它提供了一个虚方法Post(),这个方法会接收委托方法并且执行它。而对于WinForm的情况会提供WinFormSynchronizationContext,它会覆盖掉虚方法Post(),并且在子类中Post()调用Control.BeginInvoke;对于WPF或者Silverlight,会提供子类DispatcherSynchronizationContext,同样覆盖掉虚方法Post(),并且在子类Post中调用Dispatcher.Run。

public static void DoWork(Control c) { ThreadPool.QueueUserWorkItem(delegate     { .....c.BeginInvoke(delegate         { .....//对UI的操作        });     }); }如果替换成SynchronizationContext去写就成了这样:public static void DoWork(SynchronizationContext sc) { ThreadPool.QueueUserWorkItem(delegate     { … // do work on ThreadPool sc.Post(delegate         { … // do work on UI }, null);     }); } 或者如下public static void DoWork() { var sc = SynchronizationContext.Current; ThreadPool.QueueUserWorkItem(delegate     { … // do work on ThreadPool sc.Post(delegate         { … // do work on the original context }, null);    }); }

 

ExecutionContext VS SynchronizationContext

对比两者你会发现它们都会在异步操作时捕获当前线程环境上下文,但后续操作不一样,ExecutionContext会调用delegate方法并在执行时在另一个线程中恢复该线程环境状态。而SynchronizationContext仅仅是用当前捕获的环境信息去调用委托方法,这个委托方法怎么什么时候执行,在哪执行,怎么执行都取决于底层的具体实现。

注意:

 以下CodeProject文章中有一点讲得不太准确,根据惯例,如果一个线程的当前 SynchronizationContext 为 null,那么它隐式具有一个默认 SynchronizationContext。默认 SynchronizationContext 将其异步委托列队到 ThreadPool,但在调用线程上直接执行其同步委托。因此,其上下文包含所有 ThreadPool 线程以及调用 Send 的任何线程。此上下文“借用”调用 Send 的线程,将它们放入其上下文,直至委托完成。从这种意义上讲,默认上下文可以包含进程中的所有 线程。所以UI应用程序通常有两个同步上下文,一个是UI线程的SynchronizationContext,另一个是包含ThreadPool线程的默认SynchronizationContext。

 

一般遇到疑问,首先去百度国内论坛,但是继而回去CodeProject相关文章去佐证,好多文章都是从Codeproject上翻译或者浓缩出来的,但这次事件我才发现CodeProject上文章也不靠谱,虽然那上边有好多微软MVP和其他大公司的技术人员,微软的东西还是得去MSDN blog或者 MSDN Magzine上比较靠谱,尤其是看到Anders Hejlsberg, Stephen Toub, Erick Lippert, Herb Sutter审阅,就知道这是质量的保证。备忘完毕,还有半天时间,接着去深挖这块东西。

 

reference:

转载于:https://www.cnblogs.com/salomon/archive/2012/06/28/2567339.html

你可能感兴趣的文章
判断两个字符串是否相等【JAVA】
查看>>
直播技术细节3
查看>>
《分布式服务架构:原理、设计于实战》总结
查看>>
java中new一个对象和对象=null有什么区别
查看>>
字母和数字键的键码值(keyCode)
查看>>
IE8调用window.open导出EXCEL文件题目
查看>>
Spring mvc初学
查看>>
有意思的代码片段
查看>>
C8051开发环境
查看>>
VTKMY 3.3 VS 2010 Configuration 配置
查看>>
01_1_准备ibatis环境
查看>>
windows中修改catalina.sh上传到linux执行报错This file is needed to run this program解决
查看>>
JavaScript中的BOM和DOM
查看>>
360浏览器兼容模式 不能$.post (不是a 连接 onclick的问题!!)
查看>>
spring注入Properties
查看>>
【BZOJ-2295】我爱你啊 暴力
查看>>
【BZOJ-1055】玩具取名 区间DP
查看>>
Bit Twiddling Hacks
查看>>
Windwos中的线程同步
查看>>
LeetCode : Reverse Vowels of a String
查看>>