2013-02-11 87 views
6

我們有一個WPF和/或Winforms客戶端正在使用的庫。通過異步同步避免死鎖並防止UI響應

我們已經提供了類似的異步方法:我們也(不幸)提供的同步封裝方法

Task<int> GetIntAsync() 

int GetInt(); 

基本上只是調用異步方法和調用其任務是.Result

我們最近意識到,在某些情況下,需要在主UI線程上運行GetIntAsync中的某些代碼(它需要使用標記爲「Single」線程模型的傳統COM組件(即組件必須運行在主STA線程不是任何STA線程)

所以問題是,當GetInt()被稱爲主線程,它會僵局因爲

  • .Result塊爲主線,
  • GetIntAsync()中的代碼使用Dispatcher.Invoke嘗試在主線程上運行。

同步方法已被佔用,因此將其刪除將是一個突破性更改。相反,我們選擇在我們的同步GetInt()方法中使用WaitWithPumping以允許調用主線程來工作。

這個工作正常,除了從他們的UI代碼中使用GetInt()的客戶端。以前,他們預計使用GetInt()會使其UI停止響應 - 也就是說,如果他們從按鈕的單擊事件處理程序中調用GetInt(),則他們會希望在處理程序返回之前不會處理任何Windows消息。現在消息被抽出,他們的UI 響應,同樣的按鈕可以再次點擊(他們可能沒有編寫他們的處理程序是可重入的)。

如果有一個合理的解決方案,我們希望不會有我們的客戶需要在通話過程中的代碼對用戶界面響應於GetInt

問:

  • 是否有方法做WaitWithPumping,將泵「調用主」消息,但不泵其他UI相關的消息?
  • 如果客戶端用戶界面的行爲與當前顯示的模式對話框一樣,儘管處於隱藏狀態(即用戶無法訪問其他窗口),那就足夠了。但是,從我閱讀的內容來看,您無法隱藏模式對話框。
  • 你可以想到其他解決方法,將不勝感激。

回答

4

不使用現有的消息泵,您可以在GetInt的上下文中創建自己的消息泵。 Here是一個博客文章,討論如何寫一個。 This is the full solution the blog creates

使用,你可以把它寫成:

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

這將導致徹底阻斷UI線程不如預期,同時還確保所有從GetIntAsync稱爲延續不死鎖,因爲他們會被封到另一個SynchronizationContext。另請注意,此消息泵仍在主STA/UI線程上運行。

+0

謝謝。我確實看到了UI塊。不幸的是,試圖進入主線程的代碼使用主線程的Dispatcher Dispatcher.Invoke來進入主線程。我猜想做這個工作,我需要將該代碼更改爲使用SynchronizationContext,而不是主線程的Dispatcher。有什麼辦法可以使它與主線程的Dispatcher一起工作嗎? – 2013-02-12 17:33:28

+0

@MattSmith你的代碼沒有特別的工作,因爲你正在使用主線程的調度程序。 – Servy 2013-02-12 18:28:42