gpt4 book ai didi

c# - 多线程任务读取列表,导致索引超出范围

转载 作者:行者123 更新时间:2023-12-03 12:49:27 24 4
gpt4 key购买 nike

有一个案例,应用系统需要每1分钟向在线用户发布消息,代码使用多线程任务读取消息列表。但程序运行不正确,会抛出索引超出范围异常。请有人提出任何建议,谢谢。

private Timer taskTimer;
private static readonly object _locker = new object();
private static IList<Message> _messages = null;

private void OnTimerElapsed(object sender)
{
var msgModel = new MessageModel();
_messages = msgModel.GetMessageList();
var msgCount = _messages.Count();

Task[] _tasks = new Task[msgCount];
for (int i = 0; i < msgCount; i++)
{
if (i < msgCount)
{
_tasks[i] = Task.Factory.StartNew(() =>
{
lock (_locker)
{
PushMessage(i);
}
});
}
}

//waiting all task finished
while (_tasks.Any(t => !t.IsCompleted)) { }
}

private void PushMessage(int i)
{
var msg = _messages[i]; //it will throw an exception here...
//send message to on line users.
SendToOnlineUsers(msg);
}

Error:
Index was out of range. Must be non-negative and less than the size of the collection.

StackTrace Details:
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at WebIM.Hubs.BackgroudPushServiceTimer.PushMessage(Int32 i) in ...
at WebIM.Hubs.BackgroudPushServiceTimer.<>c__DisplayClass6.<OnTimerElapsed>b__2() in ...
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()

如果消息数为4,则PushMessage函数中的索引也为4,则超出范围。

最佳答案

问题在于您正在捕获 i,这是一个其值随时间变化的变量。您可以通过在循环内制作本地副本来修复它:

for (int i = 0; i < msgCount; i++)
{
int copyOfI = i;
if (i < msgCount)
{
_tasks[i] = Task.Factory.StartNew(() =>
{
lock (_locker)
{
PushMessage(copyOfI);
}
});
}
}
也就是说,我怀疑有更干净的方法来处理这个问题 - 特别是当您创建多个都使用相同锁的任务时。您实际上并没有在这里实现任何并发,然后您正在等待一切完成 - 那么为什么您要经历所有这些麻烦呢?

您还应该将 Task.WhenAll/Task.WaitAll 视为等待任务完成的更有效方法。

编辑:如果您可以并行执行此操作,请考虑使用Parallel.ForParallel.ForEach

关于c# - 多线程任务读取列表,导致索引超出范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17316461/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com