0

我正在编写一个需要通过多个计时器高速处理列表的 C# 库。我遇到了非常不稳定的错误,我尝试删除我确定包含在 List 中的元素,但程序返回以下错误:

System.IndexOutOfRangeException : 'index was outside the bounds of the array.'

我做了一个简单的例子来重现这种行为。由于该问题的随机性,我已经大力推动 List 操作,因此它会立即抛出错误。所以这个例子是必要的“怪异”。我在这里做了一个公开回购:问题示例回购

基本上,这就是我要处理的:

        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
            }
        }

我相信这是一个与线程相关的问题,好像列表计数在条件成功通过后发生了变化。

我对线程一无所知,我该如何处理这个问题?

4

1 回答 1

2

在高达 1000 的 For 循环中 - 您正在创建大约 1000 个将项目添加到列表中的计时器和 1000 个删除第一个项目的计时器。

由于您没有使用任何同步,因此会发生以下情况:- 假设 List 中有 1 个项目,并且正在执行 2 个 RemoveItems。两者都将 listCount > 0 视为 True 然后其中一个继续并删除第 0 个索引处的项目,而另一个获得异常,因为现在没有要删除的项目。

现在我不能仅通过查看代码来提出解决方案。我还需要了解意图。

这是一个教科书生产者消费者问题,因此这里的教科书建议使用 Lock 构造:

假设您有一个班级成员,例如:

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
        }
     }
}
于 2020-02-12T00:08:19.027 回答