Несколько таймеров, обрабатывающих Список на высокой скорости, вызывают проблему - PullRequest
0 голосов
/ 12 февраля 2020

Я пишу библиотеку C#, которая должна обрабатывать список с высокой скоростью через несколько таймеров. Я столкнулся с очень ошибочной c ошибкой, при которой я пытаюсь удалить элемент, который, как я знаю, наверняка содержится в списке, но программа возвращает следующую ошибку:

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

Я сделал простое пример для воспроизведения этого поведения. Из-за хаотичности, что этот вопрос, я уже надавил на операции списка, так что бросает ошибку сразу. Так что этот пример нужен «странный». Я сделал репо c здесь: Пример выпуска Репо

По сути, вот с чем я имею дело:

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

Я верю в это является проблемой, связанной с потоком, как если бы число списков изменялось ПОСЛЕ того, как условие было успешно выполнено.

Я ничего не знаю о потоке, как я могу решить эту проблему?

1 Ответ

2 голосов
/ 12 февраля 2020

В поле For l oop, которое достигает 1000 - вы создаете около 1000 таймеров, которые добавляют элемент в список, и 1000 таймеров, которые удаляют первый элемент.

Поскольку вы не использовали синхронизацию, Что происходит: - Скажем, в Списке 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
        }
     }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...