我有一个WCF双工服务,其中包含一个名为GetList的双向方法,以及一个单向回调方法ItemUpdated。
我在以下情况中发现了死锁:
我可以将我的服务的ConcurrencyMode设置为Reentrant,但这不是我需要的。我需要的是确保我的客户端在调用GetList之前没有处理来自服务的任何回调。
所以我可以同步一个对象以确保不会发生这种情况。这是我更好的选择吗?
为了澄清我当前的设计是什么,我的服务实际上是一个Windows服务,它按计划对对象列表进行一些处理,当每个项目更新时,它会引发事件ItemUpdated。此服务具有WCF服务外观,允许一个或多个控制台(客户端)订阅其事件并查看服务中发生的情况。
答案 0 :(得分:2)
InstanceContextMode = Single和ConcurrencyMode = Single会导致WCF序列化对单个实例的所有调用。换句话说,WCF已创建一个锁以强制执行序列化。这是僵局的原因。添加另一个锁可能会起作用。但是你提出了一个客户端锁定... 客户端不应该改变其线程行为以防止服务死锁。该服务需要比更强大。
这是服务问题。您应该创建一个更强大的服务。
我建议更改服务以删除序列化并完全防止死锁的可能性。我的建议(为了让我尝试):
将服务的InstanceContextMode更改为PerCall。“首选”设计是使服务无状态。为每个调用创建不同的服务实例将删除强制序列化。将所有状态信息存储在公共存储中(例如数据库或缓存)。
让服务在另一个线程上进行ItemUpdated回调。这允许服务线程在回调完成之前完成。此解决方案的问题在于,如果ItemUpdated回调引发异常,则服务不再等待捕获并处理它。这意味着更好的错误处理更难。
有关详细信息,请参阅Discover Mighty Instance Management Techniques For Developing WCF Apps。
答案 1 :(得分:0)
问题不是在服务上,而是在我客户端的回调处理程序上。这基本上就是发生的事情:
所以我最终使用CallbackBehavior属性更改了回调中的ConcurrencyMode。该服务仍然使用ConcurrencyMode = Single。