WCF 客户端由于回调而死锁,即使回调 IsOneWay 也是如此

2024-02-03

WCF 新手。

我有一个客户端在调用 WCF 服务时陷入死锁。

该服务将在调用时调用对客户端的回调,该回调被标记为 IsOneWay。我已确认该服务不会阻塞回调。

然后,客户端立即再次调用相同的服务(在紧密循环中),而无需为回调提供服务。然后客户端死锁(并且服务端的断点永远不会被触发)。

回顾一下:

CLIENT                                SERVICE
Call service -----------------------> (service breakpoint triggers)
(waiting for dispatch thread) <------ Invoke callback (IsOneWay - doesn't block)
                                      Service returns

Call service again immediately -----? (service breakpoint doesn't trigger)
(deadlock)

我假设回调已在客户端获取了一些 WCF 锁,然后来自客户端的第二个服务调用也需要该锁,因此会导致死锁。但这只是假设。

我已经阅读过有关 ConcurrencyMode 的内容,但我无法决定使用哪种模式,或者将其放在哪里,因为我不是 100% 清楚发生了什么,以及到底什么被阻止。

如果可能的话,我还希望让所有回调都由调度线程提供服务,因为这样可以使代码更简单。

WCF 专家能否解释一下到底发生了什么?

非常感谢


好吧,我想我已经怀疑了。

WCF 服务默认为单线程。所有调用和回调都被编组到单个线程(或更准确地说是 SynchronizationContext)。

我的应用程序是单线程 WPF 应用程序,因此 SynchronizationContext 设置为调度线程。

当回调到来时,它会尝试将调用编组到调度线程,这当然会阻塞原始服务调用。我不清楚它是否准确锁定,但显然在等待分派线程之前它会尝试获取一些全局锁。

当调度线程再次调用该服务时,它会在此全局锁上发生死锁。

有两种解决方法:

1) 首先在不同的线程上创建服务代理。所有调用都将通过该线程进行编组,并且调度线程被阻塞并不重要。

2) 将 [CallbackBehavior(UseSynchronizationContext = false)] 属性应用于实现回调的客户端类。这意味着当回调到来时,WCF 将忽略同步上下文,并将在任何可用线程上为其提供服务。

我选择了 2。显然,这意味着我需要编组回调,可以自己将 GUI 更新到调度线程,但幸运的是,我的回调实现无论如何都是一个小包装器,所以我只需在每个回调方法中执行一个 _dispatcher.BeginInvoke() 即可异步编组。然后,调度线程将在有机会时提供服务,这正是我首先想要的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WCF 客户端由于回调而死锁,即使回调 IsOneWay 也是如此 的相关文章

随机推荐