I need to download a few text from different urls, then I am using the CountDownEvent to handle the number of times that my event Donwnload is completed, but the thing is my CountDownEvent never is set to Zero and this remains waiting.
Any idea what is wrong with this code?
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();
}
};
}
}
}
I finally figure out how to solve my problem, the thing is despite that I am firing my download event asynchronous it seems they still are executed on the main thread, which mean that
this.CountDown.Wait()
is being invoked before that any download is completed then mythis.CountDown
is not being signaled thereforethis.CountDown
never is set to zero and this remains waiting.Here what I did:
Into the
foreach
I replaced the call to the methodLoadSources(uri)
by a ThreadPool.QueueUserWorkItem which queues a method for execution. The method executes when a thread pool thread becomes available.I also had to change the LoadSources method to fit my adjustments.
And as you can see I added a lock statement to avoid that two or more threads try to call
this.Text.Add
simultaneouslyBefore that I just declared a private object to lock on.