我正在开发一个循环浏览一系列数据库的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; }
}
答案 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;
}
}
}