目录
什么是 .NET 同步环境?
WCF 和同步环境
服务自定义同步环境
线程关联同步环境
优先级处理
回调和同步环境
为什么要使用同步环境?
Windows® Communication Foundation (WCF) 的一个比较有用的功能是它依
赖 Microsoft® .NET Framework 同步环境来封送对服务实例(或回调对象)的
调用。此机制同时为面向生产力的开发和强大的可扩展性提供支持。在本专栏中,
我将简要说明什么是同步环境,以及 WCF 如何使用它们,然后会演示可用于
扩展 WCF 的各个选项,从而以编程的方式或声明的方式使用自定义的同步环
境。除了解自定义同步环境的优点之外,您还将看到一些高级的 .NET 编程,
以及 WCF 可扩展性技术。
什么是 .NET 同步环境?
.NET Framework 2.0 引入了一个鲜为人知的功能,称为同步环境,它由
System.Threading 命名空间中的 SynchronizationContext 类定义:
复制
public delegate void SendOrPostCallback(object state);
public class SynchronizationContext
{
public virtual void Post(SendOrPostCallback callback,object state);
public virtual void Send(SendOrPostCallback callback,object state);
public static void SetSynchronizationContext
(SynchronizationContext context);
public static SynchronizationContext Current
{get;}
//More members
}
同步环境存储在线程本地存储 (TLS) 中。使用 .NET Framework 2.0 创建的每
个线程都可以有一个可通过 SynchronizationContext 的静态 Current 属性获得
的同步环境(与环境事务类似)。如果当前的线程没有同步环境,则 Current
可能会返回空值。同步环境可用来在调用线程和目标线程之间传递方法调用(万
一该方法无法在原来的调用线程上执行)。调用线程会封装其准备封送到另一个
(些)线程的方法(通过 SendOrPostCallback 类型的委托),然后分别针对
同步或异步执行,将其提供给 Send 或 Post 方法。通过调用静态方法
SetSynchronizationContext 可将同步环境与当前的线程关联起来。
迄今为止,最常见的同步环境用法与 UI 更新有关。在所有的多线程 Windows
技术中(从 MFC 到 Windows Forms,再到 WPF),只有创建了窗口的线程
才可以通过处理其消息来更新它。这个限制与 Windows 消息循环和线程消息传
递体系结构的基础用法有关。在开发多线程 UI 应用程序时,消息传递体系结构
会产生一个问题 — 您会希望在执行耗时较长的操作或接收回调时避免阻止 UI。
当然,这样就必须使用工作线程,然而那些线程却无法直接更新 UI,因为它们
不是 UI 线程。
在 .NET Framework 2.0 中,为了解决这个问题,任何基于 Windows Forms
的控件或窗体的构造函数都会查看它正在其上运行的线程是否有同步环境,如果
没有,该构造函数就会附加一个新同步环境(称为
WindowsFormsSynchronizationContext)。这个专用的同步环境可以将所有对
其 Post 或 Send 方法的调用转换成 Windows 消息,并将它们发布给要在正
确的线程上处理的 UI 线程消息队列。Windows Forms 同步环境是常用的
BackgroundWorker 帮助器控件背后的基础技术。
WCF 和同步环境
默认情况下,所有的 WCF 服务调用(以及回调)都会在 I/O Completion 线程
池中的线程上执行。该线程池在默认情况下有 1,000 个线程,但是没有一个处
于您应用程序的控制之下。现在假设有一个需要更新某些用户界面的服务。该服
务因为所处的线程不正确而不能直接访问窗体、控件或窗口。为了解决这个问题,
ServiceBehaviorAttribute 提供了 UseSynchronizationContext 属性,定义如下:
复制
[AttributeUsage(AttributeTargets.Class)]
public sealed class ServiceBehaviorAttribute : ...
{
public bool UseSynchronizationContext
{get;set;}
//More members
}
UseSynchronizationContext 的默认值设为 true。为了确定该服务应使用哪个同
步环境,WCF 会查看打开了主机的线程。如果该线程有同步环境,并且
UseSynchronizationContext 设为 true,那么 WCF 会自动将所有对该服务的
调用封送到这个同步环境。开发人员不需要与同步环境进行显式交互。WCF 实
现这一点的方式是为每个终结点的调度程序提供对同步环境的引用,然后调度程
序使用该同步环境来调度所有的调用。
例如,假设服务 MyService(在图 1 中定义)需要更新窗体 MyForm 上的一
些 UI。由于主机是在构建窗体之后打开的,因此打开的线程已经有一个同步环
境,这样对该服务的所有调用都会被自动封送到正确的 UI 线程。
Figure 1 使用 UI 同步环境
复制
[ServiceContract]
interface IMyContract
{...}
class MyService : IMyContract
{