Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步同步避免死锁并防止UI响应_C#_Wpf_Winforms_Task Parallel Library - Fatal编程技术网

C# 异步同步避免死锁并防止UI响应

C# 异步同步避免死锁并防止UI响应,c#,wpf,winforms,task-parallel-library,C#,Wpf,Winforms,Task Parallel Library,我们有一个WPF和/或Winforms客户端正在使用的库 我们提供了一种异步方法,类似于: Task<int> GetIntAsync() 它本质上只是调用异步方法并在其任务上调用.Result 我们最近意识到在某些情况下,GetIntAsync中的一些代码需要在主UI线程上运行(它需要使用标记为“单一”线程模型的遗留COM组件(即组件必须在主STA线程中运行,而不仅仅是在任何STA线程中运行) 所以问题是,当在主线程上调用GetInt()时,它将死锁 .Result阻塞主线程

我们有一个WPF和/或Winforms客户端正在使用的库

我们提供了一种异步方法,类似于:

Task<int> GetIntAsync()
它本质上只是调用异步方法并在其任务上调用
.Result

我们最近意识到在某些情况下,
GetIntAsync
中的一些代码需要在主UI线程上运行(它需要使用标记为“单一”线程模型的遗留COM组件(即组件必须在主STA线程中运行,而不仅仅是在任何STA线程中运行)

所以问题是,当在主线程上调用
GetInt()
时,它将死锁

  • .Result
    阻塞主线程
  • GetIntAsync()
    中的代码使用
    Dispatcher.Invoke
    尝试在主线程上运行
同步方法已被使用,因此删除它将是一个突破性的更改。因此,我们选择在同步
GetInt()
方法中使用

除了从UI代码中使用
GetInt()
的客户机之外,这一切都可以正常工作。以前,他们认为使用
GetInt()
会使UI无响应——也就是说,如果调用
GetInt()
在按钮的单击事件处理程序中,他们希望在处理程序返回之前不会处理任何windows消息。现在消息被压缩,他们的UI响应良好,可以再次单击同一按钮(他们可能没有将处理程序编码为可重入者)

如果有合理的解决方案,我们不希望我们的客户在调用
GetInt

问题:

  • 是否有一种方法可以执行
    WaitWithPumping
    ,它将输出“Invoke to main”消息,但不会输出其他与UI相关的消息
  • 就我们的目的而言,如果客户端UI的行为与当前显示的模式对话框一样,尽管是隐藏的(即用户无法访问其他窗口),那么就足够了。但是,从我所了解的情况来看,您无法隐藏模式对话框
  • 你能想到的其他解决办法将不胜感激

您可以在
GetInt
的上下文中创建自己的消息泵,而不是使用现有的消息泵。这是一篇讨论如何编写消息泵的博客文章

使用它,您可以将其编写为:

public int GetInt()
{
    return AsyncPump.Run(() => GetIntAsync());
}

这将导致按预期完全阻塞UI线程,同时仍然确保从
GetIntAsync
调用的所有continuations不会死锁,因为它们将被封送到不同的
SynchronizationContext
。还要注意,此消息泵仍在主STA/UI线程上运行。

谢谢。我确实看到了UI b锁定。不幸的是,试图到达主线程的代码正在使用主线程的Dispatcher
Dispatcher。调用
来到达主线程。我猜要实现这一点,我需要将该代码改为使用SynchronizationContext,而不是主线程的Dispatcher。有什么方法可以让它在h主线程的调度程序?@MattSmith您的代码无法正常工作,因为您正在使用主线程的调度程序。
public int GetInt()
{
    return AsyncPump.Run(() => GetIntAsync());
}