2009-01-24 60 views
7

我有第三方庫包含一個異步執行函數的類。該類從窗體繼承。該功能基本上基於存儲在數據庫中的數據進行計算。一旦完成,它會在調用表單中調用_Complete事件。在C中同步包裝一個異步方法#

我想要做的是同步調用函數,但從非窗體的窗體應用程序。問題是,無論我做什麼,我的應用程序塊和_Complete事件處理程序都不會觸發。從Windows窗體我可以通過使用「完整」標誌和「while(!complete)application.doevents」模擬同步運行的功能,但顯然application.doevents不適用於非Windows窗體應用程序。

是否有什麼會阻止我使用Windows窗體應用程序之外的類的方法(由於它從「窗體」繼承)? 有什麼辦法可以解決這個問題嗎?

謝謝, 邁克

+0

我不清楚。在非Windows應用程序中異步運行時,代碼是否正常運行?或者它總是無限期地在非Windows應用程序中阻塞? – Sam 2009-01-24 06:29:03

+0

在非Windows應用程序中,它會無限期地阻止,因爲_Complete事件永遠不會觸發,儘管嘗試了ManualResetEvents等。在Windows窗體應用程序中,它工作正常。 – mikecamimo 2009-01-24 07:25:37

回答

0

你有該組件的來源?這聽起來像是依賴於它將從WinForms環境中調用的事實(它必須是圖書館從Form繼承的一個很好的理由!),但很難確定。

8

在刺傷中,可能值得嘗試使用WaitHandle來阻止當前線程而不是旋轉和檢查標誌。

using System; 
using System.Threading; 

class Program 
{ 
    AutoResetEvent _autoEvent; 

    static void Main() 
    { 
     Program p = new Program(); 
     p.RunWidget(); 
    } 

    public Program() 
    { 
     _autoEvent = new AutoResetEvent(false); 
    } 

    public void RunWidget() 
    { 
     ThirdParty widget = new ThirdParty();   
     widget.Completed += new EventHandler(this.Widget_Completed); 
     widget.DoWork(); 

     // Waits for signal that work is done 
     _autoEvent.WaitOne(); 
    } 

    // Assumes that some kind of args are passed by the event 
    public void Widget_Completed(object sender, EventArgs e) 
    { 
     _autoEvent.Set(); 
    } 
} 
+0

我認爲他只是在WinForms測試工具(工作過)中做過這些工作,我認爲問題在於當它不在Winforms應用程序中時,操作永遠不會完成,因此如果它永遠不會等待要完成:) – 2009-01-24 07:05:10

1

我已經得到了一些關於這個問題的更多信息(我和mikecamimo在同一個團隊工作)。

正確複製時,Windows窗體應用程序中也會出現該問題。在原來的OP中,問題沒有發生在Windows窗體中,因爲沒有阻塞。當通過使用ResetEvent引入阻塞時,會發生同樣的問題。

這是因爲事件處理函數(Widget_Completed)與調用Widget.DoWork的方法在同一個線程上。 AutoResetEvent.WaitOne();永遠阻止,因爲事件處理程序永遠不會被調用來設置事件。

在Windows窗體環境中,這可以通過使用Application.DoEvents輪詢消息隊列並允許處理事件來解決。見下文。

using System; 
using System.Threading; 
using System.Windows.Forms; 

class Program 
{ 
    EventArgs data; 

    static void Main() 
    { 
     Program p = new Program(); 
     p.RunWidget(); 
    } 

    public Program() 
    { 
     _autoEvent = new AutoResetEvent(false); 
    } 

    public void RunWidget() 
    { 
     ThirdParty widget = new ThirdParty();     
     widget.Completed += new EventHandler(this.Widget_Completed); 
     data = null; 
     widget.DoWork(); 

     while (data == null); 
      Application.DoEvents(); 

     // do stuff with the results of DoWork that are contained in EventArgs. 
    } 

    // Assumes that some kind of args are passed by the event 
    public void Widget_Completed(object sender, EventArgs e) 
    { 
     data = e; 
    } 
} 

在非Windows窗體應用程序(例如Windows服務)中,應用程序不可用,因此無法調用DoEvents。

問題是線程和widget.DoWork的關聯事件處理程序之一需要在另一個線程之一。這應該防止AutoResetEvent.WaitOne無限期地被阻止。我想... :)

任何想法如何完成這將是太棒了。

1
AutoResetEvent _autoEvent = new AutoResetEvent(false); 

public WebBrowser SyncronNavigation(string url) 
{ 
    WebBrowser wb = null; 

    wb = new WebBrowser(); 
    wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted); 

    wb.ScriptErrorsSuppressed = true; 
    wb.Navigate(new Uri(url)); 

    while (!_autoEvent.WaitOne(100)) 
     Application.DoEvents(); 

    return wb; 
} 

void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
{ 
    //throw new NotImplementedException(); 
    _autoEvent.Set(); 
}