1

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

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 条左右的 SMS 消息(分批发送 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; }
}
4

1 回答 1

2

我的猜测是您遇到了多个线程,试图同时添加到 Recipients 并且一个在前一个完成之前开始。

尝试在读写期间锁定您的收件人,看看是否有帮助:

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;
        }
    }
}
于 2012-12-20T21:44:35.973 回答