ManualResetEvent.WaitOne阻止所有线程

时间:2012-02-20 09:49:03

标签: multithreading silverlight windows-phone-7 webclient manualresetevent

我有以下代码

ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod);
downloadHandle.WaitOne();

DownloadAsync的位置

private void DownloadAsync(object _uri)
        {
            var url = _uri as string;
            WebClient client = new WebClient();
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
            client.DownloadStringAsync(new Uri(GLOBALS.MAIN_API_URL + url, UriKind.Absolute));
        }

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            result = e.Result;
            downloadHandle.Set();
        }

所以我的问题是downloadHandle.Set()永远不会调用。但我不明白为什么?我为DownloadAsync和downloadHandle创建了一个新线程.WaitOne()不应该阻止他。

我需要的是创建一个Sync方法而不是Async。

谢谢!

UPD:使用异步调用更新了源代码。

4 个答案:

答案 0 :(得分:4)

client.DownloadString是同步方法,因此永远不会调用您完成的处理程序。您需要调用异步版本:client.DownloadStringAsync()

您可以在msdn上阅读有关DownloadStringAsync的更多信息。将代码放入try-catch块并处理异常也是明智的,如果你依赖于这个事实,应该调用一些代码。

您的代码可能如下所示:

private void DownloadAsync(object _uri)
{
    try
    {
        var url = _uri as string;
        WebClient client = new WebClient();
        client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
        client.DownloadStringAsync(new Uri(GLOBALS.MAIN_API_URL + url, UriKind.Absolute));
    }
    catch //appropriate exception
    {
       //Handle exception (maybe set downloadHandle or report an error)
    }
}

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    result = e.Result;
    downloadHandle.Set();
}

答案 1 :(得分:2)

可能存在阻止调用完成回调方法的异常。你有没有检查它是否被调用了?

顺便说一下,你实际上并不需要在这里使用线程池 - 你可以在主线程上调用DownloadAsync(),因为它不会阻塞。

答案 2 :(得分:2)

我的猜测:你是从UI线程调用downloadHandle.WaitOne()的。如果您正在从UI事件处理程序执行代码(例如,单击按钮或导航到新页面),或者事件处理程序调用的函数,那么您就在UI线程中。

为什么这是一个问题?

果然,DownloadAsync在后​​台执行,这要归功于线程池。但是,WebClient类总是使用UI线程执行其回调(即,您的client_DownloadStringCompleted方法)...但是downloadHandle.WaitOne()阻止了这个相同的线程!

这就是为什么当你对锁定超时时,client_DownloadStringCompleted方法会被神奇地执行。

如何解决这个问题?两种解决方案。

1 /停止在主线程中执行downloadHandle.WaitOne()。它阻止了用户界面,你的应用程序变得没有响应,这是从不是一件好事。

2 /使用HttpWebRequest代替WebClientHttpWebRequest在开始下载的同一个线程上执行回调,因此您不会遇到此死锁问题。

答案 3 :(得分:0)

当您从downloadHandle.WaitOne();致电UI时阻止UI thread,因此ThreadPool将永远不会致电。转到后台:

ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod);
downloadHandle.WaitOne();