多个计时器高速处理列表会导致问题
Multiple Timers treating List at high speed causes issue
我正在编写一个 C# 库,它需要通过多个定时器高速处理一个列表。
我 运行 陷入非常不稳定的错误,我试图删除一个我确定包含在列表中的元素,但程序 returns 出现以下错误:
System.IndexOutOfRangeException : 'index was outside the bounds of the array.'
我做了一个简单的例子来重现这个行为。由于该问题的 运行domness,我努力推动 List 操作,因此它会立即抛出错误。所以这个例子是必要的“诡异”。
我在这里做了一个 public 回购:Issue Example Repo
基本上,我要处理的是:
list = new List<DummyElement>();
for (int i = 0; i < 1000; i++)
{
Timer addTimer = new Timer(0.01f);
addTimer.Start();
addTimer.Elapsed += AddItem;
Timer removeTimer = new Timer(0.01f);
removeTimer.Start();
removeTimer.Elapsed += RemoveItem;
}
void AddItem(object source, ElapsedEventArgs e)
{
list.Add(new DummyElement());
}
void RemoveItem(object source, ElapsedEventArgs e)
{
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
{
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
}
}
我认为这是一个与线程相关的问题,好像列表计数在条件成功通过后发生了变化。
我对线程一无所知,我该如何处理这个问题?
在达到 1000 的 For 循环中 - 您正在创建大约 1000 个将项目添加到列表中的计时器和 1000 个删除第一项的计时器。
由于您没有使用任何同步,所以会发生以下情况:- 假设 List 中有 1 个项目并且正在执行 2 个 RemoveItems。两者都将 listCount > 0 视为 True,然后其中一个继续并删除第 0 个索引处的项目,而另一个获得异常,因为现在没有要删除的项目。
现在我不能仅通过查看代码来提出解决方案。我也需要理解意图。
这是教科书生产者消费者问题,因此这里的教科书建议使用锁结构:
假设您有一个 class 成员,例如:
private object _lockMe = new object();
void RemoveItem(object source, ElapsedEventArgs e)
{
lock(_lockMe)
{
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
{
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
}
}
}
我正在编写一个 C# 库,它需要通过多个定时器高速处理一个列表。 我 运行 陷入非常不稳定的错误,我试图删除一个我确定包含在列表中的元素,但程序 returns 出现以下错误:
System.IndexOutOfRangeException : 'index was outside the bounds of the array.'
我做了一个简单的例子来重现这个行为。由于该问题的 运行domness,我努力推动 List 操作,因此它会立即抛出错误。所以这个例子是必要的“诡异”。 我在这里做了一个 public 回购:Issue Example Repo
基本上,我要处理的是:
list = new List<DummyElement>();
for (int i = 0; i < 1000; i++)
{
Timer addTimer = new Timer(0.01f);
addTimer.Start();
addTimer.Elapsed += AddItem;
Timer removeTimer = new Timer(0.01f);
removeTimer.Start();
removeTimer.Elapsed += RemoveItem;
}
void AddItem(object source, ElapsedEventArgs e)
{
list.Add(new DummyElement());
}
void RemoveItem(object source, ElapsedEventArgs e)
{
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
{
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
}
}
我认为这是一个与线程相关的问题,好像列表计数在条件成功通过后发生了变化。
我对线程一无所知,我该如何处理这个问题?
在达到 1000 的 For 循环中 - 您正在创建大约 1000 个将项目添加到列表中的计时器和 1000 个删除第一项的计时器。
由于您没有使用任何同步,所以会发生以下情况:- 假设 List 中有 1 个项目并且正在执行 2 个 RemoveItems。两者都将 listCount > 0 视为 True,然后其中一个继续并删除第 0 个索引处的项目,而另一个获得异常,因为现在没有要删除的项目。
现在我不能仅通过查看代码来提出解决方案。我也需要理解意图。
这是教科书生产者消费者问题,因此这里的教科书建议使用锁结构:
假设您有一个 class 成员,例如:
private object _lockMe = new object();
void RemoveItem(object source, ElapsedEventArgs e)
{
lock(_lockMe)
{
int listCount = list.Count;
if (listCount > 0) // This condition is successfully passed, so there is at least one element on the list
{
list.RemoveAt(0); // This line throw an IndexOutOfRangeException error
}
}
}