【发布时间】:2015-05-29 14:01:37
【问题描述】:
我有一个要向其中倾倒项目的 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 并通过了布尔值,那么锁就在那里,所以两个线程都不会同时遍历堆栈。但是一旦第二个通过锁,堆栈将是空的并且不做任何事情。所以这最终给了我我想要的行为。
所以实际上我只是在 ConcurrentStack 周围编写一个伪并发包装器,而且似乎必须有一种不同的方法来实现这一点。想法?
【问题讨论】:
-
您真的需要按顺序处理每个元素吗?如果它们可以同时处理,只需委托给线程池,该线程池将有效地处理其工作队列。
-
你不需要锁。它是一个 ConcurrentStack,它可以被多个线程修改。如果您真的想在等待时阻塞,请使用 BlockingCollection。默认情况下它使用 ConcurrentQueue 但您可以指定不同的并发集合,例如 ConcurrentStack
-
@PanagiotisKanavos 我知道它是由多个线程修改的。我希望添加多个线程,但只能从中获取一个。这就是为什么我要锁定 pop(在“//handle whatever...”后面混淆)而不是 push。
-
@BenManes 是的,它们特别不能同时处理。
-
@claudekennilol 你想做什么?如果您只想要 一个 消费者,请不要添加多个 - 例如使用 ActionBlock 或消费者的单例实例。否则,您将获得循环处理,所有消费者都等到堆栈清空
标签: c# multithreading concurrency