【问题标题】:ThreadPool - WaitAll 64 Handle LimitThreadPool - WaitAll 64 句柄限制
【发布时间】:2010-11-22 06:12:23
【问题描述】:

我试图绕过 .net 3.5 强加的 wait64 句柄限制

我看过这个帖子:Workaround for the WaitHandle.WaitAll 64 handle limit?

所以我理解大意,但我遇到了困难,因为我没有使用委托,而是使用了

我基本上是在处理这个例子: http://msdn.microsoft.com/en-us/library/3dasc8as%28VS.80%29.aspx

此链接http://www.switchonthecode.com/tutorials/csharp-tutorial-using-the-threadpool 类似,但跟踪任务的 int 变量也是成员变量。

在上面的例子中,我应该在哪里传递 threadCount 整数? 我是否将它作为对象传递给回调方法?我认为我在使用回调方法和通过引用传递时遇到了问题。

谢谢斯蒂芬,

该链接对我来说并不完全清楚。

让我发布我的代码以帮助自己澄清:

for (int flows = 0; flows < NumFlows; flows++)
{
ResetEvents[flows] = new ManualResetEvent(false);
ICalculator calculator = new NewtonRaphson(Perturbations);
Calculators[flows] = calculator;
ThreadPool.QueueUserWorkItem(calculator.ThreadPoolCallback, flows);
}
resetEvent.WaitOne();

我将在哪里传递我的 threadCount 变量。我认为它需要在calculator.ThreadPoolCallback 中递减?

【问题讨论】:

  • 对不起,我相信我的意思是第一个链接中的“threadCount”。
  • 次要技术点:64 个句柄的限制是由 Win32 API 施加的,而不是 .NET 3.5。因此,Windows 上的每个程序都有相同的限制。

标签: c# multithreading threadpool


【解决方案1】:

您不应使用多个等待句柄来等待ThreadPool 中的多个工作项完成。它不仅不可扩展,您最终会遇到 WaitHandle.WaitAll 方法施加的 64 个句柄限制(正如您已经完成的那样)。在这种情况下使用的正确模式是计数等待句柄。通过CountdownEvent 类在.NET 3.5 的Reactive Extensions 下载中提供了一个。

var finished = new CountdownEvent(1);
for (int flows = 0; flows < NumFlows; flows++) 
{ 
  finished.AddCount();
  ICalculator calculator = new NewtonRaphson(Perturbations); 
  Calculators[flows] = calculator; 
  ThreadPool.QueueUserWorkItem(
    (state) =>
    {
      try 
      { 
        calculator.ThreadPoolCallback(state); 
      }
      finally 
      { 
        finished.Signal(); 
      }
    }, flows);
} 
finished.Signal();
finished.Wait();

【讨论】:

    【解决方案2】:

    匿名方法可能是最简单的:

    int threadCount = 0;
    for (int flows = 0; flows < NumFlows; flows++)
    {
        ICalculator calculator = new NewtonRaphson(Perturbations);
        Calculators[flows] = calculator;
    
        // We're about to queue a new piece of work:
        //    make a note of the fact a new work item is starting
        Interlocked.Increment(ref threadCount);
        ThreadPool.QueueUserWorkItem(
            delegate
            {
                calculator.ThreadPoolCallback(flows);
    
                // We've finished this piece of work...
                if (Interlocked.Decrement(ref threadCount) == 0)
                {
                    // ...and we're the last one.
                    // Signal back to the main thread.
                    resetEvent.Set();
                }
            }, null);
    }
    resetEvent.WaitOne();
    

    【讨论】:

    • 如果您查看提供的链接,您会发现我试图避免使用匿名方法。
    • 我不明白您为什么要避免使用匿名方法——您的目标是 .NET 1.0 还是 1.1 运行时?
    • 这里有一个非常微妙的错误。 WaitOneInterlocked.Decrement 将竞争导致 WaitOne 过早返回,如果最后一个工作项已排队并且在循环的下一次迭代有机会 Interlocked.Increment 之前完成.
    • 解决方案非常简单。将排队线程视为工作项。在循环之前递增threadCount,在循环之后递减并发出信号,就像工作项一样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 1970-01-01
    相关资源
    最近更新 更多