队列添加多值时出现入队错误,长时间运行触发System.ArgumentException
先看你遇到的错误栈:
System.ArgumentException: length
at System.Array.Copy (System.Array sourceArray, System.Int32 sourceIndex, System.Array destinationArray, System.Int32 destinationIndex, System.Int32 length) [0x000c3] in:0
at System.Collections.Generic.Queue`1[T].SetCapacity (System.Int32 capacity) [0x0001e] in...
这个错误几乎都是**多线程并发操作非线程安全的Queue<T>**导致的。.NET自带的System.Collections.Generic.Queue<T>本身没有内置线程同步机制,当多个线程同时执行入队(Enqueue)、出队(Dequeue)操作,或者队列触发自动扩容(也就是调用SetCapacity方法)时,内部的数组状态会被破坏,进而在Array.Copy时传入了非法的length参数,最终抛出这个异常。
给你两个靠谱的解决方案:
1. 改用线程安全的ConcurrentQueue
这是最推荐的方案,.NET在System.Collections.Concurrent命名空间下提供了专门的线程安全队列,它不需要你手动处理锁逻辑,内部已经做好了并发同步。替换起来也很简单:
原来的代码:
Queue<YourType> queue = new Queue<YourType>(); queue.Enqueue(yourValue);
改成:
using System.Collections.Concurrent; ConcurrentQueue<YourType> queue = new ConcurrentQueue<YourType>(); queue.Enqueue(yourValue);
如果需要出队,用TryDequeue方法即可:
if (queue.TryDequeue(out YourType item)) { // 处理出队的item }
2. 手动加锁保护普通Queue的所有操作
如果因为某些原因必须使用普通的Queue<T>,那你需要确保所有对队列的读写操作都在同一个锁的保护下。比如:
private readonly Queue<YourType> _queue = new Queue<YourType>(); private readonly object _queueLock = new object(); // 入队操作 public void EnqueueItem(YourType item) { lock (_queueLock) { _queue.Enqueue(item); } } // 出队操作 public bool TryDequeueItem(out YourType item) { lock (_queueLock) { if (_queue.Count == 0) { item = default; return false; } item = _queue.Dequeue(); return true; } }
注意:所有访问队列的地方都必须加锁,包括读取Count属性、遍历队列等操作,否则还是会出现并发问题。
另外,极端情况下内存不足也可能导致扩容失败,但这种情况非常罕见,优先排查多线程并发的问题即可。
内容的提问来源于stack exchange,提问作者Krishna Prasad

