Mat*_*ith 6 c# wpf winforms task-parallel-library
我们有一个由WPF和/或Winforms客户端使用的库.
我们提供了一个类似于的异步方法:
Task<int> GetIntAsync()
Run Code Online (Sandbox Code Playgroud)
我们(不幸的是)还提供了一个同步包装器方法:
int GetInt();
Run Code Online (Sandbox Code Playgroud)
它本质上只是调用异步方法并调用.Result
其任务.
我们最近在某些情况下意识到GetIntAsync
需要在主UI线程上运行一些代码(它需要使用标记为"单个"线程模型的传统COM组件(即组件必须在主STA线程中运行而不是任何STA线程)
所以问题是,当GetInt()
被称为主线程,它会死锁,因为
.Result
块为主线,GetIntAsync()
使用Dispatcher.Invoke
尝试在主线程上运行.同步方法已被消耗,因此删除它将是一个重大变化.因此,我们选择在同步方法中使用WaitWithPumpingGetInt()
来允许调用主线程.
除了使用GetInt()
UI代码的客户端之外,这种方法很好.以前,他们预计使用GetInt()
会使他们的UI无法响应 - 也就是说,如果他们GetInt()
从按钮的click事件处理程序中调用,他们会期望在处理程序返回之前不会处理任何Windows消息.现在,消息被泵送,其UI 是响应和相同的按钮可以再次点击(他们可能没有编写自己的处理程序是重入).
如果有一个合理的解决方案,我们希望我们的客户不需要在调用期间针对响应的UI进行编码 GetInt
题:
WaitWithPumping
将"调用主要"消息,但不泵送其他UI相关的消息?您可以在 的上下文中创建自己的消息泵,而不是利用现有的消息泵GetInt
。 这是一篇讨论如何编写的博客文章。 这是博客创建的完整解决方案。
使用它你可以将其写为:
public int GetInt()
{
return AsyncPump.Run(() => GetIntAsync());
}
Run Code Online (Sandbox Code Playgroud)
这将导致按预期完全阻塞 UI 线程,同时仍然确保所有调用的延续GetIntAsync
不会死锁,因为它们将被编组到不同的SynchronizationContext
. 另请注意,此消息泵仍在主 STA/UI 线程上运行。