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

发布于 2024-11-14 07:39:43 字数 805 浏览 3 评论 0原文

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 专家能否解释一下到底发生了什么?

非常感谢

new to WCF.

I have a client which is deadlocking when calling a WCF service.

The service will invoke a callback to the client at the time of the call which is marked as IsOneWay. I have confirmed that the service is not blocking on the callback.

The client then immediately calls the same service again (in a tight loop), without having yet serviced the callback. The client then deadlocks (and a breakpoint on the service side never gets triggered).

So to recap:

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)

I am assuming that the callback has grabbed some WCF lock at the client end, and then the second service call from the client also wants that lock, so deadlock results. But this is just assumption.

I have read about ConcurrencyMode but I can't decide which mode to use, or where to put it because I'm not 100% clear on what is going on, and what is being blocked exactly.

I would also prefer to keep all callbacks being serviced by the dispatch thread if possible as it keeps the code simpler.

Can any WCF experts shed light on exactly what is going on here?

Many thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眼角的笑意。 2024-11-21 07:39:43

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

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

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

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

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

有两种解决方法:

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

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

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

OK, think I've sussed it.

WCF services default to single threaded. All calls and callbacks get marshalled to a single thread (or SynchronizationContext to be more accurate).

My app is a single threaded WPF app, so the SynchronizationContext gets set to the dispatch thread.

When the callback comes in it tries to marshal the call to the dispatch thread, which of course is sat blocking on the original service call. I'm not clear it locks exactly, but there's obviously some global lock that it tries to get before waiting for the dispatch thread.

When the dispatch thread then calls the service again, it deadlocks on this global lock.

Two ways around it:

1) Create the service proxy on a different thread in the first place. All calls will get marshalled through this thread instead and it won't matter that the dispatch thread is blocked.

2) Apply [CallbackBehavior(UseSynchronizationContext = false)] attribute to the client class that implements the callback. This means WCF will ignore the synchronisation context when the callback comes in, and it will service it on any available thread.

I went with 2. Obviously this means I need to marshal callbacks that could update the GUI to the dispatch thread myself, but luckily my callback implementation is a small wrapper anyway, so I just do a _dispatcher.BeginInvoke() in each callback method to marshal ASYNCHRONOUSLY. The dispatch thread will then service when it gets a chance which is what I wanted in the first place.

梦断已成空 2024-11-21 07:39:43

您所描述的序列类似于同步调用。在异步调用中,顺序将是:

Client                            Server
Call service    --------------->ProcessRequest(1) //Your for loop for instance.
Call service    --------------->ProcessRequest(2)
Call service    --------------->ProcessRequest(3)
Call service    --------------->ProcessRequest(4)
Call service    --------------->ProcessRequest(5)

Callback awake  <---------------Response1 //Responses tends to pour in...
Callback awake  <---------------Response2
Callback awake  <---------------Response3
Callback awake  <---------------Response4...

在每个异步 Web 服务调用的每种情况下,系统都会创建一个单独的 IO 线程(IOCP 线程),并处理请求。在这种情况下,你很少会发现僵局。

我发现这种方式,即使在循环内调用,也能很好地工作。

例如,您可以注册事件 .OnProcessComplete,然后调用 ProcessCompleteAsync 方法。

The sequence that you have depicted resembles a synchronous call. While in an async call, the sequence would be:

Client                            Server
Call service    --------------->ProcessRequest(1) //Your for loop for instance.
Call service    --------------->ProcessRequest(2)
Call service    --------------->ProcessRequest(3)
Call service    --------------->ProcessRequest(4)
Call service    --------------->ProcessRequest(5)

Callback awake  <---------------Response1 //Responses tends to pour in...
Callback awake  <---------------Response2
Callback awake  <---------------Response3
Callback awake  <---------------Response4...

In each case of each async web service call, the system creates a separate IO thread(IOCP thread), and processes the request. In this, seldom you will find a deadlock.

I have found this way, even when called within a loop, to be working very well.

You can, for instance, register for the event .OnProcessComplete, and then call the ProcessCompleteAsync method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文