异步死锁 - 不是标准死锁



我称某些方法为死锁。现在我不知道为什么会这样。我不认为这是一个标准的死锁,因为我在 Main 方法中调用 Task.Result - 而不是在 UI 线程中。更重要的是,我还尝试使用异步主,而无需调用任务。但结果是一样的。

问题出在WinForms项目上。一切都从 Main 方法开始:

bool res = Task.Run(() => contr.RegisterPremiseAllInOne()).Result;

这是对新任务中的异步方法RegisterPremiseAllInOne的imple调用。

接下来会发生什么...RegisterPremiseAllInOne的工作方式更像这样(简化模型(:

public async Task<bool> RegisterPremiseAllInOne()
{
AppUser loggedAppUser = await appUserContr.GetLoggedAppUser(); // <-- everything works fine here
if(loggedAppUser == null)
return false;
var premises = await GetPremisesForLoggedUser(); //at the end there is a deadlock
}

我现在将向您展示每个方法的调用(所有内容最终都以对 WebAPI 的 rest 查询结束(:

GetLoggedAppUser -> 
await API.Users.GetLoggedAppUser() -> 
await ClientHelper.GetObjectFromRequest<Appuser>("AppUsers/logged") -> 
await SendAsyncRequest() -> 
await HttpClient.SendAsync()

我希望这是相当可读的。

这条路效果很好。有趣的是,GetPremisesForLoggedUserGetLoggedAppUser部分收敛,看起来像这样:

GetPremisesForLoggedUser -> 
await API.Premises.GetForLoggedUser() -> 
await ClientHelper.GetListFromRequest<premise>("premises/logged") -> 
await SendAsyncRequest() -> 
await HttpClient.SendAsync()

如您所见,有一条笔直的路径。调用 API 并最终发送 http 请求。

死锁距离HttpClient不到SendAsync。我不知道为什么。然而,第一条路径工作正常。

在服务器端,一切都很好。服务器返回成功响应。但是客户端挂起了。

我认为它应该有效。我不将同步与异步代码混合在一起。所有方法都返回Task<T>并标记为异步。

也许有人知道问题可能在哪里?也许你会想从调试窗口中看到一些屏幕截图:并行堆栈/任务?

好的,多亏了@usr,@Evk我发现了这个错误。然而,这是标准的UI死锁,但伪装得很少。

就在我打电话给GetPremisesForLoggedUser()之前,我正在使用工厂(IoC 容器(创建一个表单:

IPremisePickerView view = objFactory.Resolve<IPremisePickerView>();
var premises = await GetPremisesForLoggedUser();

创建窗体时,此窗体所属的线程将自动成为 UI 线程。我认为这是在表单类中完成的。

原来我在打电话 await GetPremisesForLoggedUser((

在 UI 线程上。所以可能所有任务都开始在 UI 线程上运行(从某个点开始(。但这是否意味着在 Main 中调用的 Task.Run.Result 阻塞了等待结果的 UI 线程?我不确定,如果这是在主线程上调用的(在这种情况下不是 UI 线程(。因此,如果有人能弥补我的答案,那就太好了。

无论如何,在将表单创建移动到对异步方法的调用下方后,一切都开始工作。

最新更新