2008-09-24 64 views
3

我正在研究QueueProcessor从队列中检索Command Pattern对象并在新线程中执行它的工作队列处理器的设计。管理多线程工作队列处理器内的ThreadPool饥饿吗?

我想让我的头周围的嵌套命令可能导致死锁的潜在队列锁定方案。

E.G.

FooCommand对象被放置到QueueProcessor然后在其自己的线程中执行的队列中。

正在执行的FooCommand将BarCommand放置到队列中。

假设允许的最大线程数仅为1个线程,由于FooCommand无限等待BarCommand完成,QueueProcessor将处于死锁状态。

如何管理这种情况?队列对象是作业的正确对象吗?是否有任何制衡措施可以解决这个问题?

非常感谢。 (应用程序使用C#.NET 3.0)

+0

为什么要执行将BarCommand放入队列的FooCommand将其锁定?你的意思是当一个命令在另一个线程中执行时整个队列将被锁定? – cruizer 2008-09-24 07:25:36

回答

1

对于像这样的简单情况,可以根据需要分离更多线程的附加监视线程很有帮助。

基本上每隔N秒检查一下,看看是否有任何工作已经完成,如果没有,添加另一个线程。

这不一定能处理更复杂的死锁问题,但它会解决这个问题。

我对较重问题的建议是限制等待新产生的进程,换句话说,你只能等待你开始的东西,这样你永远不会死锁,因为在这种情况下循环是不可能的。

2

你可以重新设计一些东西,这样FooCommand不会使用队列来运行BarCommand,而是直接运行它,或者你可以将FooCommand拆分成两个,并且在排队BarCommand之后立即停止,并且让BarCommand排队在完成其工作后拥有FooCommand。

2

队列隐含地假定异步执行模型。通过等待命令退出,您正在同步工作。

也许你可以将命令分成三部分:FooCommand1执行到BarCommand必须发送,BarCommand和最后FooCommand2在BarCommand完成后继续。这三个命令可以分开排队。当然,BarCommand应该确保FooCommand2已经排队。

1

如果你正在构建的队列对象自己有一些事情你可以尝试:

  1. 动态添加新的服务线程。如果可用线程数已经为零太长时间,则使用计时器并添加一个线程。
  2. 如果某个命令试图排队另一个命令并等待结果,那么应该在同一个线程中同步执行第二个命令。如果第一个线程简单地等待第二个线程,那么无论如何你都不会获得并发的好处。
1

我假设你想对BarCommand进行排队,因此它能够与FooCommand并行运行,但BarCommand在稍后的某个点上需要结果。如果是这种情况,那么我会推荐使用Parallel Extensions库中的Future。

Bart DeSmet对此有一个good blog entry。基本上你想这样做:


public void FooCommand() 
{ 
    Future<int> BarFuture = new Future<int>(() => BarCommand()); 

    // Do Foo's Processing - Bar will (may) be running in parallel 

    int barResult = BarFuture.Value; 

    // More processing that needs barResult 
} 

随着像并行扩展这样的libararies,我会避免“滚动你自己的”调度。