Pergunta

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();
                }
            };
        }
    }
}
Foi útil?

Solução

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 my this.CountDown is not being signaled therefore this.CountDown never is set to zero and this remains waiting.

Here what I did:

Into the foreach I replaced the call to the method LoadSources(uri) by a ThreadPool.QueueUserWorkItem which queues a method for execution. The method executes when a thread pool thread becomes available.

ThreadPool.QueueUserWorkItem(new WaitCallback(LoadSources), (object)uri);

I also had to change the LoadSources method to fit my adjustments.

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();
            } 
        }
    };
}

And as you can see I added a lock statement to avoid that two or more threads try to call this.Text.Add simultaneously

Before that I just declared a private object to lock on.

private Object thisLock = new Object();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top