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(使用前将#替换为@)