我正在研究工作队列处理器的设计,其中QueueProcessor从队列中检索命令模式对象并在新线程中执行它。
我试图了解一个潜在的Queue锁定场景,其中嵌套的命令可能会导致死锁。
E.G。
将一个FooCommand对象放在队列中,然后QueueProcessor在自己的线程中执行。
执行FooCommand将BarCommand置于队列中。
假设允许的最大线程数只有1个线程,QueueProcessor将处于死锁状态,因为FooCommand无限期等待BarCommand完成。
如何管理这种情况?队列对象是作业的正确对象吗?是否有任何制衡措施可以解决这个问题?
非常感谢。 (应用程序使用C#.NET 3.0)
答案 0 :(得分:2)
你可以重新设计一些东西,以便FooCommand不使用队列来运行BarCommand但是直接运行它,或者你可以将FooCommand分成两部分,并且在排队BarCommand之后立即停止前半部分,并且让第二部分具有BarCommand队列FooCommand在完成它的工作之后。
答案 1 :(得分:2)
排队隐式假设一个异步执行模型。通过等待命令退出,您正在同步工作。
也许您可以将命令分为三个部分:执行的FooCommand1直到BarCommand必须发送,BarCommand和BarCommand完成后继续执行的FooCommand2。这三个命令可以单独排队。当然,BarCommand应该确保FooCommand2排队。
答案 2 :(得分:1)
对于像这样的简单情况,可以根据需要分离更多线程的附加监视线程是有帮助的。
基本上每N秒检查一次作业是否已完成,如果没有,则添加另一个作业。
这不一定能处理更复杂的死锁问题,但它会解决这个问题。
我对更重问题的建议是限制等待新生成的进程,换句话说,你只能等待你开始的事情,这样你永远不会遇到死锁,因为在那种情况下循环是不可能的。
答案 3 :(得分:1)
如果您自己构建Queue对象,可以尝试一些事项:
答案 4 :(得分: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
}
对于像Parallel Extensions这样的库,我会避免“滚动你自己的”调度。