【问题标题】:Should I use a lock to prevent a WCF deadlock in this situation?在这种情况下我应该使用锁来防止 WCF 死锁吗?
【发布时间】:2012-08-30 19:15:03
【问题描述】:

我有一个 WCF 双工服务,它带有一个名为 GetList 的 2 路方法,以及一个单路回调方法 ItemUpdated。

我在以下情况中检测到死锁:

  1. 服务调用 ItemUpdated 回调,在客户端由 OnItemUpdated 方法处理。
  2. 在上一个方法返回之前,一些用户交互导致客户端调用服务上的 GetList。

我可以将我的服务的 ConcurrencyMode 设置为 Reentrant,但这不是我需要的。我需要确保我的客户端在调用 GetList 之前没有处理来自服务的任何回调。

所以我可以同步锁定一个对象以确保不会发生这种情况。这是我更好的选择吗?

更新:

只是为了澄清我当前的设计是什么,我的服务实际上是一个 Windows 服务,它按计划对对象列表进行一些处理,当每个项目更新时,它会引发事件 ItemUpdated。该服务有一个 WCF 服务外观,它允许一个或多个控制台(客户端)订阅其事件并查看服务中发生了什么。

【问题讨论】:

  • 你现在的 ConcurrencyMode 和 InstanceMode 是什么?
  • 很可能,“锁定”只会让事情变得更糟 :) 像“双向”和“双工”这样的词可能很可怕——你的服务应该被设计为 无状态,如果可能的话。双向消息 - 当然。一台主机上的一件事正在等待另一台主机的某事:请重新访问您设计的协议。 肯定查看 ErnieL 的回复,并阅读他发布的链接。这是个好建议,恕我直言...
  • @paulsm4:我更新了我的问题以澄清我当前的设计。正如我在那里提到的,我的服务是 Windows 服务,因此它不能真正是无状态的。另外,我看不出双向(相对于单向)方法有多可怕。我承认双工服务更难设计和维护,如何将它们用于提供者-订阅者模式可能是一个值得商榷的决定。

标签: .net wcf duplex


【解决方案1】:

InstanceContextMode = Single 与 ConcurrencyMode = Single 一起导致 WCF 序列化对单个实例的所有调用。换句话说,WCF 创建了一个锁来强制执行序列化。这就是死锁的原因。添加另一个锁可能会起作用。但是您提出了客户端锁定... 客户端不必更改其线程行为以防止服务死锁。该服务需要比这更强大

这是一个服务问题。您应该创建一个更强大的服务。

我建议更改服务以删除序列化并完全防止死锁的可能性。我的建议(为了我会尝试):

  1. 将服务的 InstanceContextMode 更改为 PerCall。“首选”设计是让服务无状态。为每个调用创建不同的服务实例可以消除强制序列化。将所有状态信息存储在一个公共存储中(例如数据库或缓存)。

  2. 让服务在不同的线程上进行 ItemUpdated 回调。这允许服务线程在回调完成之前完成。此解决方案的问题在于,如果 ItemUpdated 回调抛出异常,则服务不再等待捕获和处理它。这意味着良好的错误处理更难。

更多信息请参见Discover Mighty Instance Management Techniques For Developing WCF Apps

【讨论】:

    【解决方案2】:

    问题实际上不在服务上,而是在我客户端的回调处理程序上。基本上就是这样:

    1. 我的服务引发了一个在客户端调用 ItemUpdated 的事件。
    2. 当回调仍在处理 ItemUpdated 时,用户强制执行 GetList。
    3. 服务收到请求并返回 GetList 的结果,但我的客户端无法处理来自服务的响应,因为它已经在处理另一个回调。

    所以我最终使用 CallbackBehavior 属性更改了回调中的 ConcurrencyMode。服务保持 ConcurrencyMode = Single。

    【讨论】:

      猜你喜欢
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      • 2012-04-24
      • 2021-07-09
      • 2011-01-17
      • 2022-07-22
      • 2013-01-17
      • 2013-10-16
      相关资源
      最近更新 更多