Szy*_*mon 8 c# wcf multithreading web-services locking
我们有一个WCF Web服务操作,用于生成PDF文件.我们正在使用第三方工具(Syncfusion),我们目前可能无法取代它.
问题是,第三方工具似乎存在多线程问题,并且在某些情况下,当同时多次调用Web服务时,它不起作用.
我们可以通过使用lock并确保只有一个线程执行临界区来解决问题:
Public Class GeneratorController
{
// object we use for lock
private static Object thisLock = new Object();
public void Generate(ref PdfDocument pdfDocument)
{
lock (thisLock)
{
// critical section
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:这是一个好主意吗?如果我们在Web服务中有这样的代码会导致任何问题吗?
注意
这不是关于Syncfusion的问题.这是关于lock在Web服务中使用的问题.请不要将标签更改为syncfusion.
我在这里看到的问题是资源匮乏.
围绕锁没有FIFO规则.因此,如果持续加载,您可以得到以下情况:
A声称锁定B等待锁定C等待锁定A释放锁.锁是任意给予线程的CD等待锁定.现在你有线程B,D两个都在等待.C释放锁.即使通过线程B等待时间最长,锁也是随意给予线程的D.所以它一直持续到WCF调用超时,并且你得到一个不可能重现的错误.
如果我必须实现这一点,我将有一个专门用于生成PDF文件的工作线程.该服务首次启动时将启动该线程,并等待从作业队列中取出作业.每个WCF查询都会在此队列上发出请求,并且在它知道已处理作业之前,它会有一些阻止的方式.
.NET 4.0提供了BlockingCollection类来帮助解决这个问题.(见这个问题)
这为您提供了没有完整解决方案的方法,因为它不是一个小问题.祝好运!
小智 4
WCF 支持同步调用您的服务对象,根据您的需要,您可能需要查看以下两个属性:
如果您无法启动第3方组件的多个实例,并且该组件不允许并发访问(最坏的情况),那么您可以指定InstanceContextMode = Single,并且ConcurrencyMode = Single;在这种情况下,WCF 将仅实例化 WCF 对象的单个副本(我假设它是第 3 方组件的包装器),并且一次仅处理一个请求。请求将以 FIFO 方式排队并处理。您不必在 wcf 服务内使用锁,因为 WCF 运行时确保您同步访问 wcf 对象。