3

我有以下代码

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() 不应该阻止他。

我需要的是创建一个同步方法而不是异步。

谢谢!

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

4

4 回答 4

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();
}
于 2012-02-20T09:51:22.947 回答
2

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

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

于 2012-02-20T09:51:56.867 回答
2

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

为什么这是个问题?

果然,DownloadAsync是在后台执行的,多亏了线程池。但是,WebClient 类总是使用 UI 线程执行其回调(即您的client_DownloadStringCompleted方法)...但是这个线程被您的downloadHandle.WaitOne()!

这就是为什么当你对你的锁设置一个超时时,该client_DownloadStringCompleted方法会神奇地执行。

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

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

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

于 2012-02-20T11:07:48.793 回答
0

当您downloadHandle.WaitOne();UI您的 block中调用时UI threadThreadPool将永远不会调用。移至背景:

ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod);
downloadHandle.WaitOne();
于 2012-02-20T09:52:41.700 回答