C# 目标数组不够长,无法复制集合中的所有项。检查数组索引和长度
我有这个密码。这给了我一个错误: 目标数组不够长,无法复制该数组中的所有项 收集检查数组索引和长度 我认为这是因为使用了字典,所以我将其切换到了C# 目标数组不够长,无法复制集合中的所有项。检查数组索引和长度,c#,.net,arrays,multithreading,dictionary,C#,.net,Arrays,Multithreading,Dictionary,我有这个密码。这给了我一个错误: 目标数组不够长,无法复制该数组中的所有项 收集检查数组索引和长度 我认为这是因为使用了字典,所以我将其切换到了ConcurrentDictionary,但错误仍然存在 private void SaverCallback() { AddThread("Main Thread"); const string path = "milestone"; while (!stop) { ConcurrentDictionar
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();
}
private void SaverCallback()
{
AddThread(“主线程”);
const string path=“里程碑”;
当(!停止)
{
ConcurrentDictionary里程碑=新建ConcurrentDictionary();
milestone.TryAdd(“作业”,JobQueue.Queue.MainQueue);
milestone.TryAdd(“锁定的作业”,JobQueue.Queue.LockedQueue);
再次:试试看{
使用(FileStream writingStream=newfilestream(路径,FileMode.OpenOrCreate,FileAccess.Write,FileShare.None))
{
BinaryFormatter Formatter=新的BinaryFormatter();
序列化(写流、里程碑);
writingStream.Flush();
Logger.Debug(“状态已保存”);
}
}
捕获(例外e)
{
Logger.Error($“里程碑异常:{e.Message}”);
再次转到;
}
这是等待时间(60000);
}
RemoveThread();
}
UPD:
目标数组不够长,无法复制该数组中的所有项
收集检查数组索引和长度。在
System.ThrowHelper.ThrowArgumentException(异常资源)
在System.Collections.Generic.Dictionary2.CopyTo(KeyValuePair
2[]
数组,Int32索引)位于
System.Collections.Generic.Dictionary`2.GetObjectData(SerializationInfo
信息,StreamingContext)位于
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerializate(对象
obj,ISurrogateSelector代理选择器,StreamingContext上下文,
SeroObjectInfoinit SeroObjectInfoinit,IFormatterConverter转换器,
ObjectWriter ObjectWriter,SerializationBinder绑定器)位于
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo
objectInfo、NameInfo成员NameInfo、NameInfo类型NameInfo)位于
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArrayMember(WriteObjectInfo
objectInfo,NameInfo arrayElemTypeNameInfo,对象数据)位于
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray(WriteObjectInfo
objectInfo、NameInfo成员NameInfo、WriteObjectInfo成员objectInfo)
在
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo
objectInfo、NameInfo成员NameInfo、NameInfo类型NameInfo)位于
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serializate(对象
图,标题[]inHeaders,\uu二进制编写器serWriter,布尔值fCheck)在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serializate(流 序列化流、对象图、头[]头、布尔fCheck)
在AggregateRunner.Enteties.Saver.SaverCallback()上
为了避免此错误,我在尝试序列化文件之前使用lock。
现在它工作正常了 据我所知,您每小时为队列拍摄一次快照,但代码的主要问题是您试图在没有任何克隆或同步逻辑的情况下序列化队列(我想这是一个
ConcurrentQueue
)。代码的另一个问题是goto
用法,这里根本不需要
您面临的异常是ArgumentException
,是ConcurrentQueue的CopyTo
方法的异常。它发生在序列化过程中,因为某个线程向队列添加了一些消息,现在它不适合序列化程序决定使用的数组
因此,在这种情况下,您可以在访问原始队列期间引入一些锁定(您决定这样做),或者为队列创建一个克隆,并以安全的方式序列化该克隆,而不阻塞其他线程
您可以自己使用ConcurrentQueue
方法来实现这一点,创建长度大于队列中消息数的数组,但通常锁定是克隆数据更方便的方法。因此,您的代码应该如下所示:
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();
}
private void SaverCallback()
{
AddThread(“主线程”);
const string path=“里程碑”;
当(!停止)
{
尝试
{
锁定(JobQueue.Queue.MainQueue)
锁定(JobQueue.Queue.LockedQueue)
{
使用(var writingStream=newfilestream(路径,FileMode.OpenOrCreate,FileAccess.Write,FileShare.None))
{
var里程碑=新的ConcurrentDictionary();
milestone.TryAdd(“作业”,JobQueue.Queue.MainQueue);
milestone.TryAdd(“锁定的作业”,JobQueue.Queue.LockedQueue);
var formatter=新的二进制格式化程序();
序列化(写流、里程碑);
writingStream.Flush();
Logger.Debug(“状态已保存”);
}
}
//这行云也是最后的情况,
//如果发生错误时不需要保存队列
这是等待时间(60000);
}
捕获(例外e)
{
//请注意,记录器接受整个异常信息
//而不仅仅是信息
Logger.Error($“里程碑异常:{e}”);
继续;
}
}
RemoveThread();
}
不要使用goto
。这表明了一个主要的设计问题。允许跳转的唯一语言是IL和ASM什么是JobQueue.Queue.MainQueue
和JobQueue.Queue.LockedQueue
?@MatthewWatson某种类型的线程池当作业队列被序列化为o的一部分时,另一个线程是否可以将项目添加到作业队列中