C# CountdownEvent从不设置为零

C# CountdownEvent从不设置为零,c#,asynchronous,webclient-download,countdownevent,C#,Asynchronous,Webclient Download,Countdownevent,我需要从不同的URL下载一些文本,然后我使用CountDownEvent来处理我的事件Donwnload完成的次数,但问题是我的CountDownEvent从未设置为零,这仍在等待 你知道这个代码有什么问题吗 namespace WebApplication.AsyncCall { using System; using System.Collections.Generic; using System.Net; using System.Threading;

我需要从不同的URL下载一些文本,然后我使用CountDownEvent来处理我的事件Donwnload完成的次数,但问题是我的CountDownEvent从未设置为零,这仍在等待

你知道这个代码有什么问题吗

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();
                }
            };
        }
    }
}
namespace WebApplication.AsyncCall
{
使用制度;
使用System.Collections.Generic;
Net系统;
使用系统线程;
公共部分类\u默认值:System.Web.UI.Page
{
私有倒计时事件倒计时=null;
公众倒计时事件倒计时
{
得到
{
if(this.countDown==null)
{
this.countDown=新的倒计时事件(1);
}
返回这个。倒计时;
}
}
私有列表文本=null;
公共列表文本
{
得到
{
如果(this.text==null)
{
this.text=新列表();
}
返回此.text;
}
}
受保护的无效页面加载(对象发送方、事件参数e)
{
List rssSources=新列表();
rssSources.Add(@)http://news.yahoo.com/rss/entertainment");
rssSources.Add(@)http://go.microsoft.com/fwlink/?linkid=84795&clcid=409");
foreach(rssSources中的字符串uri)
{
this.CountDown.AddCount();
加载源(uri);
}
这个.CountDown.Signal();
这个。倒计时。等等();
}
私有void加载源(字符串uri)
{
WebClient客户端=新的WebClient();
DownloadStringAsync(新Uri(Uri,UriKind.Absolute));
client.DownloadStringCompleted+=(s,a)=>
{
如果(a.Error==null&&!a.Cancelled)
{
此.Text.Add(a.Result);
这个.CountDown.Signal();
}
};
}
}
}

我终于找到了解决问题的方法,问题是尽管我正在异步触发下载事件,但它们似乎仍然在主线程上执行,这意味着
this.CountDown.Wait()
在任何下载完成之前被调用,然后my
this.CountDown
没有被通知,因此
this.CountDown
从未被设置为零,这仍在等待

以下是我所做的:

foreach
中,我将对方法
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();
            } 
        }
    };
}
如您所见,我添加了一个lock语句,以避免两个或更多线程同时调用
this.Text.Add

在此之前,我只声明了一个要锁定的私有对象

private Object thisLock = new Object();

异步调用是否在添加侦听器之前完成?尝试移动
client.DownloadStringAsync(新Uri(Uri,UriKind.Absolute))
LoadSources
方法的末尾,看看是否有效。是否确实调用了回调?编辑:另外,您可以尝试在while循环中轮询
CountDown
的值,而不是使用
this.CountDown.Wait()以帮助调试。如果下载过程中出现任何错误,则不会发出
倒计时信号。另外,两个回调可能同时在不同的线程上执行,对
this.Text.Add的调用将由两个不同的线程同时调用。这可能会导致一些严重的问题。谢谢你的建议,我将添加一个锁定语句以避免出现这种情况。