定时器上的异步任务。如何避免重叠?

Asynchronous tasks on a Timer. How to avoid overlapping?

我正在使用计时器每 {n} 秒向服务器请求一次消息。 我收到一些异常,我认为这些异常与我收集的消息不是线程安全的有关。

我闻到有腥味,但我不确定最好的处理方法是什么。

代码看起来类似于:

        ThreadPool.QueueUserWorkItem(delegate
        {
            while (true)
            {
                try
                {
                    DoSomething1();    
                    DoSomething2();                     
                }
                catch (Exception ex)
                {
                    LogManager.GetLogger(GetType()).Error("Exception caught in " + GetType().Name, ex);
                }
                finally
                {                        
                    Thread.Sleep(TimeSpan.FromSeconds(20));
                }
            }  
        });

    private void DoSomething1()
    {
        messages.AddRange(server.GetMessages());
        ParseMessages();
        messages.Clear();
    }

有时在执行 AddRange 时出现此错误:

System.ArgumentException: Source array was not long enough. Check srcIndex and length, and the array's lower bounds. at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable) at System.Collections.Generic.List1.set_Capacity(Int32 value) at System.Collections.Generic.List1.EnsureCapacity(Int32 min) at System.Collections.Generic.List1.InsertRange(Int32 index, IEnumerable1 collection) at System.Collections.Generic.List1.AddRange(IEnumerable1 collection)

我认为这是因为消息列表在另一个计时器调用时被修改了?

如果您在多个线程中有多个生产者,请使用某种锁定机制(如 lock 关键字)或更好地使用 Thread-Safe Collections 中的线程安全集合。还要确保 server.GetMessages() 没有返回 null.

您似乎可以使用 ConcurrentQueue<T>(自 .NET 4.0 以来的开箱即用的内置线程安全集合)来执行相同的工作。如果您正在解析消息,您可能会按顺序解析它们,因此,FIFO 应该适合您。