2011-05-27 55 views
5

讓我們暫時擱置一下,question是否應該在Silverlight應用程序的上下文中嘗試類似同步的操作。如果我在下面的代碼中使用的ManualResetEvent爲:爲什麼ManualResetEvent無法在使用Silverlight 4的此同步調用中工作?

static string result; 
    static AutoResetEvent are = new AutoResetEvent(false); 
    static ManualResetEvent mre = new ManualResetEvent(false); 
    public static string AsyncCall() 
    { 
     string url = "https://stackoverflow.com/feeds/tag/silverlight"; 
     WebClient w = new WebClient(); 
     w.DownloadStringCompleted += new DownloadStringCompletedEventHandler(w_DownloadStringCompleted); 
     w.DownloadStringAsync(new Uri(url), url); 
     mre.WaitOne(); 
     return result; 
    } 

    static void w_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 
    { 
     result = e.Result; 
     mre.Set(); 
    } 

正如你所期望從閱讀ManualResetEvent on MSDN,「如果控制線程完成的活動,它調用設置方法,以表示該等待的線程可以繼續。」 ,當在w_DownloadStringCompleted中調用Set()時,控制權返回到開始在AsyncCall中等待的等待線程。這是使用.NET 4.0運行時發生的情況。 AsyncCall中的線程被阻塞,直到下載完成並調用Set。

如果我在Silverlight 4中運行同一段代碼,DownloadStringAsync將被調用,但控件永遠不會到達w_DownloadStringCompleted回調。一旦調用了WaitOne(),那麼AsyncCall中的那個線程就掛在那裏,並且啓動來處理DownloadStringAsync的線程永遠不會到達回調。我看到一個線程到達SL4中的下載回調的唯一方法是,如果AsyncCall的線程從AsyncCall返回。所以Set()永遠不會被調用。

爲什麼ManualResetEvent在Silverlight 4中無法按預期工作?它爲什麼不同於.NET 4? 這可能是微軟對異步設計模式的強制執行嗎? 或者有什麼我失蹤?

感謝

+0

你在調試器中看到了什麼? – SLaks 2011-05-27 02:41:50

+0

如果我點擊Break All,我看到調試器停留在WaitOne(),並且線程中只有一個線程。 – 2011-05-27 02:47:55

回答

3

在Silverlight中的網絡回調,因爲他們起源於同一個線程總會到達。例如,如果您在UI線程(即按鈕單擊事件)上創建WebClient.DownloadStringAsync,則回調調用將排隊等待在同一UI線程上傳遞。但是,對mre.WaitOne()的調用阻塞了UI線程,因此從不調用回調,並且調用永遠不會發生。

所以,是的,這是一種網絡電話異步執行 - 你真的不能做同步調用,即使他們似乎是同步的。

+0

你的意思是你不能在主UI線程上進行同步調用嗎?因爲我最近發現如果在不同的線程上執行同步調用,我可以如何進行同步調用。但是,在所有情況下,它看起來好像在主UI線程上進行的ManualResetEvent.Wait()調用將阻止所有異步網絡調用,即使它們是在不同的線程上創建的。 – 2011-05-27 12:46:26

+1

正確,你確實真的不能在UI線程上進行同步調用。這實際上會導致應用程序「掛起」,這正是決定不允許同步呼叫的原因。 – carlosfigueira 2011-05-27 14:23:01

+0

加1強調你確實真的不能同步呼叫。 – 2011-05-29 04:49:20

相關問題