实例管理
并发就像两个人同时去银行取钱,他们同时输入取钱数,同时确定取钱,同时完成取钱,但是银行的账户上表现却只减少了一个人的钱,这是并发。WCF并发管理能过确保服务执行在特定的线程,它提供了自动同步和手动同步两种方式,并发一号ServiceBehavior的ConcurrenyMode来负责并发方式,
ConcurrenyMode.Single WCF提供自动同步,并通过关联服务的实例和同步锁禁止并发调用
ConcurrenyMode.Multipe WCF不会管理服务,因此,WCF支持并发调用
ConcurrenyMode.Reentrant 与ConcurrenyMode.Single类似,设计它的目的是避免重入存在的潜在死锁
1.ConcurrenyMode.Multipe可以利用Monitor(封送在lock语句总)支持锁定对象,还可以利用MethodImplOptions.Sysnchronized标志的MethodImpl特征标记服务操作对实例加锁,如:
[ServiceBehavior(ConcurrenyMode=ConcurrenyMode.Multipe)]
class MyService:IMyService
{
[MethodImpl(MethodImplOptions.Sysnchronized)]
public void MyMethod()
{
...
}
}
2.设置为ConcurrenyMode.Multipe或ConcurrenyMode.Reentrant,如果存在TransactionScopeRequired=true,则服务行为的ReleaseServiceOnTransactionComplete必须设置为false;
3.ConcurrenyMode.Reentrant主要是在WCF服务需要调用双向回调到正在调用的客户端使用,如果设置为ConcurrenyMode.Single则可能抛出异常
实例与并发访问
对相同客户端调用的并发处理,一服务配置的实例模式,服务并发模式和配置的传递方式,即服务绑定和会话模式有关。
在单调服务中,如果绑定为basicHttpBinding绑定,或任意一种WS绑定,同时契约为SessionMode.NotAllowed或SessionMode.Allowed,并没有安全与可靠的消息传输,则单调服务运行对调用进行并发处理;如果绑定为TCP或IPC,或WS绑定,且SessionMode.Allowed,并包含安全可靠的消息传输,或WS绑定,且SessionMode.Required,则调用并发处理与并发模式有关。
对于会话服务,单独配置的并发模式负责管理未决调用的并发执行。
资源与服务
使用ConcurrenyMode.Single或者一个显式的同步锁同步访问服务实例时,只能管理对服务实例状态自身的同步访问,不无法为正在使用的重要资源提供安全的访问,
对于死锁,可以配置为ConcurrenyMode.Single和InstranceContextMode.Single避免死锁的发生,因为单例服务同一时间只有一个客户端,在访问资源时,其他实例则处于死锁状态。另外还可以降低锁的数量来降低死锁的发生,这是需要我们配置ConcurrenyMode.Multipe从而避免使用WCF提供的锁。
资源同步上下文
默认情况下服务线程不依赖与宿主所在的线程,所以服务一一个线程或多个线程存在关联关系,服务就不能只在传入的WCF工作线程进行调用,服务需要将调用封送到正确线程。.NET2.0引入了同步上下文概念,在System.Threading中定义了SynchronizationContext类,以代表同步上下文。此类实现的同步模型的目的是使公共语言运行时内部的异步/同步操作能够针对不同的异步模型采取正确的行为。此模型还简化了托管应用程序为在不同的同步环境下正常工作而必须遵循的一些要求。
首先,我们需要获取资源的同步上下文(即SynchronizationContext实例获取资源创建的SynchronizationContext类的属性),然后创建一个调用方法的SendOrPostCallback类型委托,最后调用SynchronizationContext的send()方法封送给同步上下文
UI同步上下文
Windows启动Application.Run();方法时,应用程序就生产一个主窗体,还会安装WindowsFormsSynchronizationContext作为当前线程的同步上下文,WindowsFormsSynchronizationContext将Send()或Post()转换为窗体消息,和上面讲的一样,创建一个调用方法的SendOrPostCallback类型委托,最后调用SynchronizationContext的send()方法封送给同步上下文
服务同步上下文
ServiceBehavior提供 UseSynchronizationContext属性,默认为true,即自动将传入的调用封送到服务的同步上下文。
UI线程上托管服务
我们应该在UI线程上托管服务,因为UI线程创建了需要交互的窗体和控件,我们需要在装载窗体之前,让服务需要交互的窗体去打开宿主。我们甚至可以将窗体自身当成服务实现托管,但是必须将窗体定义为单例服务。
访问窗体可以使用Application.OpenForms集合查找正确窗体,一旦拥有就可以访问它了,还可以创建静态变量存储自身的副本,我们可以使用ThreadStatic将静态变量标记为线程相关,线程相关的静态变量总是线程安全的
定制服务同步上下文
开发一个定制服务上下文包含两个方面:首先是实现定制的同步上下文,WCF提供AffinitySynchronizer类创建工作线程,并维持一个包含工作线程的同步队列。然后再利用声明方式将它安装到应用程序服务上,调用SynchronizationContext的静态方法SetSynchronizationContext()。一旦宿主被打开,宿主就会使用提供的同步上下文
如下:
SynchronizationContext synchronizationcontext=new AffinitySynchronizer();
SynchronizationContext.SetSynchronizationContext(synchronizationcontext);
using (ynchronizationcontext as IDisposable)
{
ServiceHost host=new ServiceHost(typeof(MyService))
host.Open();
/*执行阻塞操作*/
host.Close();
}
注:以上文章大部分拮取自《WCF服务编程》。