我们有一个供WPF和/或Winforms客户使用的库。
我们提供了类似于:
的异步方法Task<int> GetIntAsync()
我们(不幸的是)也提供了一个同步包装器方法:
int GetInt();
基本上只调用异步方法并在其任务上调用.Result
。
我们最近意识到在某些情况下GetIntAsync
中的某些代码需要在主UI线程上运行(它需要使用标记为“单个”线程模型的旧COM组件(即组件必须运行)在主STA线程中,而不仅仅是任何STA线程)
所以问题是当在主线程上调用GetInt()
时,它会死锁,因为
.Result
阻止主线程,GetIntAsync()
中的代码使用Dispatcher.Invoke
尝试在主线程上运行。已经消耗了同步方法,因此删除它会是一个重大变化。因此,我们选择在同步GetInt()
方法中使用WaitWithPumping来允许调用主线程。
除了从其UI代码中使用GetInt()
的客户端之外,此方法正常。以前,他们预计使用GetInt()
会使他们的UI无响应 - 也就是说,如果他们从按钮的click事件处理程序中调用GetInt()
,他们会希望在处理程序返回之前不会处理任何Windows消息。现在消息被抽取,他们的UI 响应,并且可以再次点击相同的按钮(并且他们可能没有将其处理程序编码为可重入)。
如果有合理的解决方案,我们希望我们的客户不需要在调用GetInt
期间针对响应的用户界面进行编码
问题:
WaitWithPumping
来抽取“调用主要”消息,但不能提取其他与UI相关的消息?答案 0 :(得分:4)
您可以在GetInt
的上下文中创建自己的消息泵,而不是使用现有的消息泵。 Here是一篇博客文章,讨论如何撰写一篇文章。 This is the full solution the blog creates
使用它你可以写成:
public int GetInt()
{
return AsyncPump.Run(() => GetIntAsync());
}
这将导致按预期完全阻止UI线程,同时仍然确保从GetIntAsync
调用的所有延续都不会死锁,因为它们将被封送到不同的SynchronizationContext
。另请注意,此消息泵仍在主STA / UI线程上运行。