在多线程工作队列处理器中管理ThreadPool饥饿?

时间:2008-09-24 07:22:41

标签: c# .net multithreading

我正在研究工作队列处理器的设计,其中QueueProcessor从队列中检索命令模式对象并在新线程中执行它。

我试图了解一个潜在的Queue锁定场景,其中嵌套的命令可能会导致死锁。

E.G。

将一个FooCommand对象放在队列中,然后QueueProcessor在自己的线程中执行。

执行FooCommand将BarCommand置于队列中。

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

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

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

5 个答案:

答案 0 :(得分:2)

你可以重新设计一些东西,以便FooCommand不使用队列来运行BarCommand但是直接运行它,或者你可以将FooCommand分成两部分,并且在排队BarCommand之后立即停止前半部分,并且让第二部分具有BarCommand队列FooCommand在完成它的工作之后。

答案 1 :(得分:2)

排队隐式假设一个异步执行模型。通过等待命令退出,您正在同步工作。

也许您可以将命令分为三个部分:执行的FooCommand1直到BarCommand必须发送,BarCommand和BarCommand完成后继续执行的FooCommand2。这三个命令可以单独排队。当然,BarCommand应该确保FooCommand2排队。

答案 2 :(得分:1)

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

基本上每N秒检查一次作业是否已完成,如果没有,则添加另一个作业。

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

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

答案 3 :(得分:1)

如果您自己构建Queue对象,可以尝试一些事项:

  1. 动态添加新服务线程。如果可用的线程数已经为零,则使用计时器并添加一个线程。
  2. 如果某个命令正在尝试排队另一个命令并等待结果,那么您应该在同一个线程中同步执行第二个命令。如果第一个线程只是等待第二个线程,那么无论如何都不会获得并发效益。

答案 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这样的库,我会避免“滚动你自己的”调度。