【问题标题】:Destination array is not long enough to copy all the items in the collection. Check array index and length目标数组的长度不足以复制集合中的所有项目。检查数组索引和长度
【发布时间】:2017-08-19 21:23:07
【问题描述】:

我有这个代码。它给了我一个错误:

目标数组不够长,无法复制 收藏。检查数组索引和长度。

我还以为是用字典的原因,所以切换到ConcurrentDictionary,但是还是出现了错误。

private void SaverCallback()
{
    AddThread("Main Thread");
    const string path = "milestone";
    while (!stop)
    {
        ConcurrentDictionary<string, object> milestone = new ConcurrentDictionary<string, object>();
        milestone.TryAdd("Jobs", JobQueue.Queue.MainQueue);
        milestone.TryAdd("Locked Jobs", JobQueue.Queue.LockedQueue);

    again: try {
            using (FileStream writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
            {
                BinaryFormatter formater = new BinaryFormatter();
                formater.Serialize(writingStream, milestone);
                writingStream.Flush();
                Logger.Debug("Status saved");
            }
        }
        catch(Exception e)
        {
            Logger.Error($"Milestone exception: {e.Message}");
            goto again;
        }
        this.WaitTime(60000);
    }
    RemoveThread();
}

UPD:

目标数组不够长,无法复制 收藏。检查数组索引和长度。并且在 System.ThrowHelper.ThrowArgumentException(异常资源资源) 在 System.Collections.Generic.Dictionary2.CopyTo(KeyValuePair2[] 数组,Int32 索引)在 System.Collections.Generic.Dictionary`2.GetObjectData(SerializationInfo 信息,StreamingContext 上下文)在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(对象 obj,ISurrogateSelector surrogateSelector,StreamingContext 上下文, SerObjectInfoInit serObjectInfoInit,IFormatterConverter 转换器, ObjectWriter objectWriter, SerializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo 对象信息,名称信息成员名称信息,名称信息类型名称信息)在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArrayMember(WriteObjectInfo objectInfo,NameInfo arrayElemTypeNameInfo,对象数据)在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray(WriteObjectInfo objectInfo、NameInfo memberNameInfo、WriteObjectInfo memberObjectInfo) 在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo 对象信息,名称信息成员名称信息,名称信息类型名称信息)在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(对象 图,Header[] inHeaders,__BinaryWriter serWriter,布尔 fCheck)
在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(流 序列化流、对象图、Header[] 标头、布尔 fCheck)
在 AggregateRunner.Enteties.Saver.SaverCallback()

【问题讨论】:

  • 不要使用goto。它表明一个主要的设计问题。唯一允许跳转的语言是 IL 和 ASM
  • JobQueue.Queue.MainQueueJobQueue.Queue.LockedQueue的类型是什么?
  • @MatthewWatson 某种线程池
  • 那么,作为milestone 序列化的一部分,另一个线程是否可以将项目添加到作业队列中?如果是这样,那么在这个过程中可能发生了一些不好的事情。
  • 所以,如果有异常,记录它并重试,使用 goto,无限。听起来不好吗?

标签: c# .net arrays multithreading dictionary


【解决方案1】:

据我所知,您每小时为队列拍摄一次快照,但您的代码的主要问题是您正在尝试序列化队列(我猜这是 ConcurrentQueue&lt;T&gt; ) 本身没有任何克隆或同步逻辑。您的代码的另一个问题是 goto 用法,这里根本不需要。

您面临的异常是 ArgumentException 并且是 ConcurrentQueue&lt;T&gt;CopyTo 方法的 third possible exception。它在序列化期间发生,因为某些线程将一些消息添加到队列中,现在它不适合数组序列化器决定使用。

因此,在这种情况下,您可以做的是在访问原始队列期间引入一些锁定(您决定这样做),或者为您的队列创建一个克隆并以安全的方式将其序列化而不阻塞其他队列线程。

您可以自己使用ConcurrentQueue&lt;T&gt;CopyTo 方法来执行此操作,创建长度大于队列中消息数的数组,但通常锁定是克隆数据的更方便的方法。所以你的代码应该是这样的:

private void SaverCallback()
{
    AddThread("Main Thread");
    const string path = "milestone";
    while (!stop)
    {
        try
        {
            lock (JobQueue.Queue.MainQueue)
            lock (JobQueue.Queue.LockedQueue)
            {
                using (var writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
                {
                    var milestone = new ConcurrentDictionary<string, object>();
                    milestone.TryAdd("Jobs", JobQueue.Queue.MainQueue);
                    milestone.TryAdd("Locked Jobs", JobQueue.Queue.LockedQueue);

                    var formater = new BinaryFormatter();
                    formater.Serialize(writingStream, milestone);
                    writingStream.Flush();
                    Logger.Debug("Status saved");
                }
            }
            // this line cloud be in finally case too,
            // if you don't need to save a queue in case of some errors
            this.WaitTime(60000);
        }
        catch(Exception e)
        {
            // note that logger accepts whole exception information
            // instead of only it's message
            Logger.Error($"Milestone exception: {e}");
            continue;
        }
    }
    RemoveThread();
}

【讨论】:

    【解决方案2】:

    为了避免这个错误,我在尝试序列化文件之前使用了锁。 现在它可以正常工作了。

    【讨论】:

      猜你喜欢
      • 2016-04-08
      • 2022-01-23
      • 1970-01-01
      • 2019-09-12
      • 2020-03-16
      • 1970-01-01
      • 2018-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多