我需要从不同的网址下载一些文本,然后我使用CountDownEvent来处理我的事件Donwnload完成的次数,但事情是我的CountDownEvent永远不会被设置为零,这仍然在等待。 / p>
知道这段代码有什么问题吗?
namespace WebApplication.AsyncCall
{
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
public partial class _Default : System.Web.UI.Page
{
private CountdownEvent countDown = null;
public CountdownEvent CountDown
{
get
{
if (this.countDown == null)
{
this.countDown = new CountdownEvent(1);
}
return this.countDown;
}
}
private List<string> text = null;
public List<string> Text
{
get
{
if (this.text == null)
{
this.text = new List<string>();
}
return this.text;
}
}
protected void Page_Load(object sender, EventArgs e)
{
List<string> rssSources = new List<string>();
rssSources.Add(@"http://news.yahoo.com/rss/entertainment");
rssSources.Add(@"http://go.microsoft.com/fwlink/?linkid=84795&clcid=409");
foreach (string uri in rssSources)
{
this.CountDown.AddCount();
LoadSources(uri);
}
this.CountDown.Signal();
this.CountDown.Wait();
}
private void LoadSources(string uri)
{
WebClient client = new WebClient();
client.DownloadStringAsync(new Uri(uri, UriKind.Absolute));
client.DownloadStringCompleted += (s, a) =>
{
if (a.Error == null && !a.Cancelled)
{
this.Text.Add(a.Result);
this.CountDown.Signal();
}
};
}
}
}
答案 0 :(得分:0)
我终于弄明白了如何解决我的问题,尽管我正在异步解雇我的下载事件,但似乎它们仍然在主线程上执行,这意味着在此之前调用了this.CountDown.Wait()
下载完成后我的this.CountDown
未发出信号,因此this.CountDown
永远不会设置为零,这仍然在等待。
我在这里做了什么:
进入foreach
我用ThreadPool.QueueUserWorkItem替换了对方法LoadSources(uri)
的调用,该方法将一个方法排队执行。该方法在线程池线程可用时执行。
ThreadPool.QueueUserWorkItem(new WaitCallback(LoadSources), (object)uri);
我还必须更改LoadSources方法以适应我的调整。
private void LoadSources(object uri)
{
WebClient client = new WebClient();
client.DownloadStringAsync(new Uri(uri.ToString(), UriKind.Absolute));
client.DownloadStringCompleted += (s, a) =>
{
lock (thisLock)
{
try
{
if (a.Error == null && !a.Cancelled)
{
this.Text.Add(a.Result);
}
}
finally
{
this.CountDown.Signal();
}
}
};
}
正如您所看到的,我添加了一个锁定语句,以避免两个或多个线程同时调用this.Text.Add
在此之前,我刚刚声明了一个私有对象来锁定。
private Object thisLock = new Object();