在本系列的上一篇文章中,我们重点讨论了线程关联性对service和callback的操作执行的影响:在service host的时候,可以设置当前线程的SynchronizationContext,那么在默认情况下,service操作的执行将在该SynchronizationContext下执行(也就将service操作包装成delegate传入SynchronizationContext的Send或者Post方法);同理,对于Duplex同行方式来讲,在client调用service之前,如果设置了当前线程的SynchronizationContext,callback操作也将自动在该SynchronizationContext下执行。
对于Windows Form Application来讲,由于UI Control的操作执行只能在control被创建的线程中被操作,所以一这样的方式实现了自己的SynchronizationContext(WindowsFormsSynchronizationContext):将所有的操作Marshal到UI线程中。正因为如此,当我们通过Windows Form Application进行WCF service的host的时候,将会对service的并发执行带来非常大的影响。
详细讲,由于WindowsFormsSynchronizationContext的Post或者Send方法,会将目标方法的执行传到UI主线程,所以可以说,所有的service操作都在同一个线程下执行,如果有多个client的请求同时抵达,他们并不能像我们希望的那样并发的执行,而只能逐个以串行的方式执行。
一、通过实例证明线程关联性对并发的影响
我们可以通过一个简单的例子证明:在默认的情况下,当我们通过Windows Form Application进行service host的时候,service的操作都是在同一个线程中执行的。我们照例创建如下的四层结构的WCF service应用:
1、Contract:IService
namespace Artech.ThreadAffinity2.Contracts
{
[ServiceContract]
public interface IService
{
[OperationContract]
void DoSomething();
}
}
2、Service:Service
namespace Artech.ThreadAffinity2.Services
{
public class Service:IService
{
public static ListBox DispalyPanel
{ get; set; }
public static SynchronizationContext SynchronizationContext
{ get; set; }
#region IService Members
public void DoSomething()
{
Thread.Sleep(5000);
int threadID = Thread.CurrentThread.ManagedThreadId;
DateTime endTime = DateTime.Now;
SynchronizationContext.Post(delegate
{
DispalyPanel.Items.Add(string.Format("Serice execution ended at {0}, Thread ID: {1}",
endTime, threadID));
}, null);
}
#endregion
}
}