我有一个ConcurrentStack,我正在将项目转储到其中。在堆栈不为空时一次处理这些项目的一种好方法是什么?我想以一种在不处理堆栈时不会占用CPU周期的方式来执行此操作。
我目前所能获得的基本上是这个,它似乎不是理想的解决方案。
private void AddToStack(MyObj obj)
{
stack.Push(obj);
HandleStack();
}
private void HandleStack()
{
if (handling)
return;
Task.Run( () =>
{
lock (lockObj)
{
handling = true;
if (stack.Any())
{
//handle whatever is on top of the stack
}
handling = false;
}
}
}
因此,bool存在,因此不会备份多个线程,而不会等待锁。但是我不希望有很多事情可以同时处理堆栈,因此不需要锁。因此,如果两个单独的线程最终同时调用了HandleStack并越过了 bool 值,那么锁就在那里,因此它们都不会立即遍历堆栈。但是,一旦第二个通过锁,堆栈将是空的,不会执行任何操作。因此,这最终给了我想要的行为。
因此,实际上我只是在ConcurrentStack周围编写一个伪并发包装器,似乎必须有一种不同的方法来实现这一目标。有什么想法吗?
最佳答案
ConcurrentStack<T>
是实现IProducerConsumerCollection<T>
的集合之一,因此可以由BlockingCollection<T>
包装。 BlockingCollection<T>
具有一些方便的成员,可用于常见操作,例如“在堆栈不为空时消费”。例如,您可以循环调用TryTake
。或者,您可以只使用GetConsumingEnumerable
:
private BlockingCollection<MyObj> stack;
private Task consumer;
Constructor()
{
stack = new BlockingCollection<MyObj>(new ConcurrentStack<MyObj>());
consumer = Task.Run(() =>
{
foreach (var myObj in stack.GetConsumingEnumerable())
{
...
}
});
}
private void AddToStack(MyObj obj)
{
stack.Add(obj);
}