异步HTTP请求在通用列表中抛出IndexOutOfRange异常

时间:2012-12-20 21:09:08

标签: c# multithreading generic-list outofrangeexception

我正在开发一个循环浏览一系列数据库的Windows服务,然后使用HTTP请求发送短信。在遍历每个数据库的方法的开头,我定义了一个通用列表,如下所示:

public static List<Recipient> Recipients = new List<Recipient>();

我使用通过线程池发送的异步HTTP请求的结果填充该列表:

//inside main method                    
foreach (var SMS in SMSJoin)
{
    ...

    SMSMessage oSMS = new SMSMessage(Keyword, Number, Message, MessageID);

    ThreadPool.QueueUserWorkItem(SendSMS, oSMS);
}

然后它被传递给下一个方法:

public static void SendSMS(object SMStoSend)
{
    try
    {
        SMSMessage oSMS = (SMSMessage)SMStoSend;
        ...
        Request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), state);
    }
    ...
}

然后到GetRequestStreamCallback ...

public static void GetRequestStreamCallback(IAsyncResult AsynchronousResult)
{
    State state = (State)AsynchronousResult.AsyncState;
    SMSMessage oSMS = state.oSMS;
    try
    {
        ...
        Request.BeginGetResponse(new AsyncCallback(ReceiveResponse), state);
    }
    ...
}

最后收到回复并将其添加到收件人列表中:

public static void ReceiveResponse(IAsyncResult Result)
{
    ...
    finally
    {
        oSMS.Complete = DateTime.Now;

        Recipient CompleteMessage = new Recipient(oSMS.MessageID, oSMS.Recipient, oSMS.ErrorCode, oSMS.Complete, oSMS.ResponseCode);
        Recipients.Add(CompleteMessage);
    }

在代码结束时,应将每个响应添加到Recipient对象,然后存储在通用列表中。问题是,一旦大约每1000条左右的短信(分批发送50条),代码行IndexOutOfRangeException就会抛出未处理的Recipients.Add(CompleteMessage)

我认为列表中没有索引,许多收件人都是重复的。为什么会抛出这个错误,为什么只有每一次都会出现这种错误?这可能与线程问题有关吗?

作为一个注释,我正在从Timer对象激活main方法,但它会等到上一个实例完成后再开始一个新实例。

修改 这是Recipient类:

public class Recipient
{
    public Recipient(long MessageID, string PhoneNumber, string ErrorMessage, DateTime? Completed, string Response)
    {
        this.MessageID = MessageID;
        this.PhoneNumber = PhoneNumber;
        this.ErrorMessage = ErrorMessage;
        this.Completed = Completed;
        this.Response = Response;
    }

    public long MessageID { get; set; }
    public string PhoneNumber { get; set; }
    public string ErrorMessage { get; set; }
    public DateTime? Completed { get; set; }
    public string Response { get; set; }
}

1 个答案:

答案 0 :(得分:2)

我的猜测是你在尝试同时添加到收件人的多个线程中运行,并且在前一个完成之前开始尝试添加一个。

尝试在读取和写入过程中锁定收件人,看看是否有帮助:

private static object mylock = new object();
private static List<Recipient> _recipients = new List<Recipient>();
public static List<Recipient> Recipients
{
    get
    {
        List<Recipient> result;
        lock (mylock)
        {
            result = _recipients;
        }
        return result;
    }
    set
    {
        lock (mylock)
        {
            _recipients = value;
        }
    }
}