Предположим, у меня есть шаблон Производитель-Потребитель, где потребитель также может производить дополнительную работу. По сути, представьте список из 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);
}
}
Я чешу голову как это не работает. Я получаю разные результаты почти каждый раз. Я должен быть в состоянии гонки, которое не вижу. Обратите внимание, что обработка списка - это не мой тестовый случай, а просто упрощение. Если есть лучший шаблон, который я мог бы использовать, я тоже все уши. Многопоточность, как видите, не моя сильная сторона.