WCF会破坏lock关键字吗?
本文关键字:关键字 lock WCF | 更新日期: 2023-09-27 18:02:21
参见http://blogs.microsoft.co.il/blogs/applisec/archive/2009/11/23/wcf-thread-affinity-and-synchronization.aspx.
给出了下面的例子,这似乎表明WCF完全破坏了c#中的lock关键字:
public class MyService : IContract
{
//author of article originally did not initialize this in his illustration
//initializing it here so that we can avoid talking about side issues.
public static object wait_handle = new object();
public int LongOperation()
{
lock (wait_handle)
{
Before(); //Thread1 has the lock
LongWait(); //Threads might be switched here
After(); // Thread2 does not have the lock but
it runs.
return 0;
}
}
public int SecondOperation()
{
// If accidently Thread1 is allocated it has the handle and would enter the lock.
lock (wait_handle)
{
DoWork();
}
return 0;
}
}
这对微软来说似乎是一个可怕的决定,因为它打破了关键字的常用用法,并且意味着我不能可靠地使用WCF服务中任何先前开发的代码库,除非我验证它们没有在代码中使用"锁"。(我假设如果这篇文章是真的,这意味着lock关键字使用了某种线程本地类型的存储)。
微软真的这么做了吗?还是我错过了什么?还是引用的文章不准确?
我认为那篇文章的作者误解了在WCF服务中缺乏线程亲和性意味着什么。MSDN上有一段节选自《编程WCF服务》这本书,专门介绍了并发性,值得一读。
简短的回答似乎是,在一个多调用并发模型中,你不能保证你在一个服务中使用的线程具有你正在寻找的所需的亲和性(例如,如果你的线程需要使用线程本地存储或者它运行在UI线程上)。你可以通过使用SynchronizationContext来特别设置它,但是一旦服务进入,调用的线程关联就被锁定了。
传入服务调用在I/O完成线程池中的工作线程上执行,与任何服务或资源线程无关。这意味着默认情况下,服务不能依赖于任何类型的线程关联(即始终由同一线程访问)。同样,默认情况下,服务不能依赖于执行由主机或服务开发人员创建的任何主机端自定义线程。
没有理由WCF下的线程可以任意停止它正在做的事情,封接它当前正在做的所有事情,并在调用的中间使用相同的上下文开始一个新线程。这将是非常危险的,并且很难提供作者所声称的那种可伸缩性。Monitor.Enter()和lock语句完全可以在WCF服务中使用,只要您的代码需要这种级别的同步。
确保锁定的是一个实例,而不仅仅是null
。
public static readonly object wait_handle = new object();
看起来您错过了一些非常重要的事情:WCF可能会也可能不会总是在同一个进程中执行。如果WCF在单个进程中运行,而您锁定了一个静态对象,那么您将拥有一个有效的锁。
另一方面,如果WCF 不是在单个进程中运行(例如,IIS托管可能会导致这种情况),那么您的锁将毫无价值,因为一个进程有锁,而另一个进程没有。WCF服务于一个非常特殊的目的:客户机-服务器通信。当然,还有更多的事情要做,但是绝大多数WCF编程都是针对SOAP或RESTful web服务的。在编写这类服务时,避免使用锁几乎总是一个好主意,因为一个服务可能同时处理多个请求,而锁将导致另一个请求暂停(这可能导致超时)。
如果您正在使用需要串行访问的资源,请找到单个服务调用的替代解决方案。