Предполагаемое использование ConcurrentBag и пустота как завершающее условие.C#

Место общения программистов C#
Anonymous
Предполагаемое использование ConcurrentBag и пустота как завершающее условие.

Сообщение Anonymous »


"ConcurrentBag(T) — это потокобезопасная реализация пакета, оптимизированная для
сценариев, в которых один и тот же поток будет одновременно создавать и потреблять
данные, хранящиеся в пакете". - MSDN


У меня есть именно такой вариант использования (несколько потоков, как потребляющих, так и производящих), но мне нужно иметь возможность эффективно и своевременно определять, когда мешок становится окончательно пустым (мои потоки производят только на основе того, что было потреблено, и пакет запускается с одним элементом до запуска потоков).

Мне трудно найти эффективный способ без условий гонки который свободен от глобальных блокировок для этого. Я считаю, что введение глобальных блокировок сведет на нет преимущества использования ConcurrentBag, в основном не требующего блокировок.

Мой фактический вариант использования — это «неупорядоченный» (двоичный) обход дерева. Мне просто нужно посетить каждый узел и выполнить очень простые вычисления для каждого из них. Меня не волнует порядок их посещения. Алгоритм должен завершиться, когда все узлы будут посещены.

Код: Выделить всё

int taskCount = Environment.ProcessorCount;
Task[] tasks = new Task[taskCount];
var bag = new ConcurrentBag();
bag.Add(root);
for (int i = 0; i < taskCount; i++)
{
int threadId = i;
tasks[threadId] = new Task(() =>
{
while(???) // Putting bag.IsEmpty>0 here would be obviously wrong as some other thread could have removed the last node but not yet added the node's "children"
{
TreeNode node;
bool success = bag.TryTake(out node);

if (!success) continue; //This spinning is probably not very clever here, but I don't really mind it.

// Placeholder: Do stuff with node

if (node.Left != null) bag.Add(node.Left);
if (node.Right != null) bag.Add(node.Right);
}
});
tasks[threadId].Start();
}
Task.WaitAll(tasks);
Так как же можно добавить к этому эффективное условие завершения? Я не против того, чтобы условие становилось дорогостоящим, когда сумка почти пуста.

Вернуться в «C#»