简体   繁体   English

如何验证异步方法和HttpClient.PostAsync调用中的死锁?

[英]How can I verify a deadlock in my async to sync method and HttpClient.PostAsync calls?

I'm having a deadlock in my program but I can't figure out why and how to fix it. 我的程序陷入僵局,但无法弄清楚为什么以及如何解决它。

Short version: 简洁版本:

An async to sync method locks waiting for an async call, which calls another, and so on until a HttpClient.PostAsync call. async sync方法锁定等待一个异步调用,该调用再调用另一个,依此类推,直到HttpClient.PostAsync调用。 The http post call never happens, at least it doesn't arrives in the server (which I own too). http调用永远不会发生,至少它不会到达服务器(我也拥有)。 No errors in the client. 客户端中没有错误。 My main questions are at the end of this SO question. 我的主要问题在本SO问题的末尾。 Thanks! 谢谢!

Longer version: 较长版本:

I know that it is very easy to come up with deadlocks and we must be careful. 我知道提出死锁很容易,我们必须小心。 I'm trying to adhere to the advices of 1. Propagate the async down to all the methods and 2. Use ConfigureAwait(false) whenever possible/make sense. 我试图遵循以下建议:1.将异步传播到所有方法,并2.尽可能/有意义地使用ConfigureAwait(false) (I think the main advocate of this is Stephen Cleary as his blog and answers in many SO which I have read many of them). (我认为主要的提倡者是Stephen Cleary,他是他的博客,并在我读过很多文章的许多SO中对此进行了回答)。

Well, my program... I cannot post a full sample code here unfortunately, it's rather long; 好吧,我的程序...不幸的是,我无法在此处发布完整的示例代码,这相当长; I describe it as a sync method A that calls an async method B , which calls another async, which calls another async, etc. Eventually the last async call is HttpClient.PostAsync . 我将其描述为一个调用异步方法B的同步方法A ,该方法B调用了另一个异步方法,该方法又调用了另一个异步方法,等等。最后一个异步调用最终是HttpClient.PostAsync

Program stop's at the await HttpClient.PostAsync . 程序在await HttpClient.PostAsync处停止。 Also, the Http post never fires (I own the target server and in this case it never receives a request). 另外,Http帖子永远不会触发(我拥有目标服务器,在这种情况下,它永远不会收到请求)。 (I double checked the uri etc.). (我仔细检查了uri等)。

As a result, the synchronous method locks waiting for B 's async task to complete which never happens. 结果,同步方法锁定等待B的异步任务完成,而这永远不会发生。 A looks like this: A看起来是这样的:

public Byte[] A()
{
var task = BAsync();
return task.GetAwaiter().GetResult();
}

I use synchronization this way as he method does not need the context back, and I saw the method suggested by Stephen in Nito is implemented using this. 我以这种方式使用同步,因为他的方法不需要上下文,并且我看到了Nito的Stephen建议的方法是使用此方法实现的。 (I also tried task.Result instead with same results). (我也尝试了task.Result而不是相同的结果)。

The code of the http post call is: http post调用的代码为:

private static async Task<HttpResponseMessage> PostAsync(Uri serverUri, HttpContent httpContent)
{
var client = new HttpClient();
return await client.PostAsync(serverUri, httpContent).ConfigureAwait(false);
}

The app's UI freezes. 应用程序的UI冻结。 It's a WP8 app. 这是WP8应用。 In this aspect, the buttons do not react to Click events but ScrollViews still work. 在这方面,按钮不对Click事件做出反应,但ScrollViews仍然有效。 This is topic for another question but I prefer to include this detail in the question. 这是另一个问题的主题,但我希望将此细节包括在问题中。

I'm not even sure I have a deadlock, or maybe is a HttpClient bug? 我什至不确定自己有死锁,还是HttpClient错误? (I don't think so, the same method is working in other workflows in the same app). (我不这么认为,相同的方法正在同一应用程序的其他工作流中工作)。

I tried to verify for deadlock and used VS's threads debugger window but only the main thread seems to be active. 我试图验证是否存在死锁,并使用了VS的线程调试器窗口,但似乎只有主线程处于活动状态。 I also tried with all other sort of debugger windows but nothing gave me a hint. 我还尝试了所有其他类型的调试器窗口,但没有任何提示。

My main questions are: 我的主要问题是:

  1. Am I having a deadlock? 我有僵局吗?
  2. How can I verify, maybe using VS, that I do have a deadlock? 如何验证(也许使用VS)我确实有死锁?
  3. Is it at Client.PostAsync ? 它在Client.PostAsync吗? If yes why and how to fix it? 如果是,为什么以及如何解决?
  4. If not, any ideas please. 如果没有,请提出任何想法。

Edit: Method A gets called using reflection with MethodInfo.Invoke . 编辑:使用MethodInfo.Invoke反射调用方法A I believe now this is part of the problem. 我相信现在这是问题的一部分。

I believe you are seeing a deadlock, though I'm not sure how to prove it. 我相信您会遇到僵局,尽管我不确定如何证明这一僵局。

HttpClient on most platforms properly uses ConfigureAwait(false) internally, but on a few platforms does not. 大多数平台上的HttpClient在内部正确使用ConfigureAwait(false) ,但在少数平台上则没有。 I believe that WP8 is one of those that does not. 我相信WP8就是其中之一。 This means that you can use ConfigureAwait(false) all you want correctly, but HttpClient can still cause a deadlock. 这意味着您可以正确使用所有需要的ConfigureAwait(false) ,但是HttpClient仍然会导致死锁。

The best solution is to go async all the way. 最好的解决方案是始终保持异步状态。 But if that's not possible, then two alternatives come to mind: 但是,如果那不可能,那么有两种选择可供考虑:

  1. Push the HttpClient work off to a background thread. HttpClient工作推送到后台线程。

     public Byte[] A() { var task = Task.Run(() => BAsync()); return task.GetAwaiter().GetResult(); } 
  2. Establish a nested loop on the foreground thread to execute any asynchronous work. 在前台线程上建立嵌套循环以执行任何异步工作。

     public Byte[] A() { return AsyncContext.Run(() => BAsync()); } 

    Note that AsyncContext is from my AsyncEx library . 请注意, AsyncContext来自我的AsyncEx库 I believe AsyncContext should work on WP8 but I haven't actually used it on that platform. 相信 AsyncContext应该可以在WP8上使用,但是我实际上并没有在该平台上使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM