C# - Многопоточная модель «производитель-потребитель», где потребитель также производит работу - PullRequest
0 голосов
/ 23 марта 2020

Предположим, у меня есть шаблон Производитель-Потребитель, где потребитель также может производить дополнительную работу. По сути, представьте список из 1000 целых чисел:

var LL = new List<int> {1, 2, 3, ....., 1000};

Я хочу многопотоковую сумму - поэтому я беру 2 числа за раз, суммируя их и добавляя результат обратно к LL. Я буду делать это до тех пор, пока не останется только 1 запись в LL, когда вернется последний ожидающий поток.

Мой экспериментальный код выглядит так:

var LL = Enumerable.Range(1, 1000).ToList();                             
Func<int, int, int> sum = (a, b) => { return a + b; };
object o = new object();
int outstandingThreads = 0;
while (LL.Count > 1 || outstandingThreads > 0)
{
    //Note that I set an upper bound of 8 simulateneous Threads
    if (LL.Count > 1 && outstandingThreads < 8)
    {
        var l1 = LL[0];
        LL.RemoveAt(0);
        var l2 = LL[0];
        LL.RemoveAt(0);
        Interlocked.Increment(ref outstandingThreads);
        var t = Task.Factory.StartNew(() =>
        {
            var rr = l1 + l2;
            // In practice I would use a ConcurrentBag and not explicitly log
            lock (o)
            {
                LL.Add(rr);                                
            }
            Interlocked.Decrement(ref outstandingThreads);

        }, CancellationToken.None,
        TaskCreationOptions.DenyChildAttach,
        TaskScheduler.Default);
    }                    
}

Я чешу голову как это не работает. Я получаю разные результаты почти каждый раз. Я должен быть в состоянии гонки, которое не вижу. Обратите внимание, что обработка списка - это не мой тестовый случай, а просто упрощение. Если есть лучший шаблон, который я мог бы использовать, я тоже все уши. Многопоточность, как видите, не моя сильная сторона.

1 Ответ

1 голос
/ 23 марта 2020

У вас есть lock около Add, но RemoveAt также является модификацией списка. Почему нет lock вокруг этого?

Может возникнуть гонка между весь список был бы излишним, поэтому список кеширует его наверняка), так как и Add, и Remove выполняют две вещи: изменяют элементы списка и обновляют .Count, даже если он не обрабатывает sh, он может получить испортил, так что да, я думаю, что это все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...