Join和WaitAll的比较

时间:2010-11-16 03:41:04

标签: c# .net multithreading

对于多线程等待,有人可以比较使用WaitHandle.WaitAllThread.Join的利弊吗?

3 个答案:

答案 0 :(得分:3)

WaitHandle.WaitAll有64个句柄限制,所以这显然是一个巨大的限制。另一方面,它是一种仅在一次通话中等待许多信号的便捷方式。 Thread.Join不需要创建任何其他WaitHandle个实例。由于它可以在每个线程上单独调用,因此64个句柄限制不适用。

就个人而言,我从未使用WaitHandle.WaitAll。当我想等待多个信号时,我更喜欢更具伸缩性的模式。您可以创建一个向上或向下计数的计数机制,一旦达到特定值,您就会发出单个共享事件的信号。 CountdownEvent类可以方便地将所有这些打包成一个类。

var finished = new CountdownEvent(1);
for (int i = 0; i < NUM_WORK_ITEMS; i++)
{
  finished.AddCount();
  SpawnAsynchronousOperation(
    () =>
    {
      try
      {
        // Place logic to run in parallel here.
      }
      finally
      {
        finished.Signal();
      }
    }
}
finished.Signal();
finished.Wait();

<强>更新

您想要从主线程发出事件信号的原因很微妙。基本上,您希望将主线程视为仅仅是另一个工作项。它毕竟与其他真正的工作项一起同时运行。

考虑一下,如果我们不将主线程视为工作项,可能会发生什么。它将经历for循环的一次迭代,并为我们的事件添加计数(通过AddCount),表明我们有一个待处理的工作项吗?让我们说SpawnAsynchronousOperation完成并获取在另一个线程上排队的工作项。现在,想象一下主线程在转向循环的下一次迭代之前是否被抢占。执行工作项的线程获得其公平的CPU份额并开始哼唱并实际完成工作项。工作项中的Signal调用会运行并将待处理的工作项计数减少到零,这会将CountdownEvent的状态更改为已发出信号。与此同时,主线程唤醒并遍历循环的所有迭代并点击Wait调用,但由于事件过早发出信号,即使仍有待处理的工作项,它仍会传递。

同样,当您将主线程视为工作项时,避免这种微妙的竞争条件很容易。这就是为什么CountdownEvent初始化为一个计数,而Signal方法在Wait之前调用。

答案 1 :(得分:1)

我喜欢@Brian的回答作为两种机制的比较。

如果您使用.Net 4,那么通过Task Parallel Library探索System.Threading.Tasks以实现任务Parellelism是值得的,它允许您在更高抽象级别跨多个线程管理任务。您在此问题中询问的用于管理线程交互的信令是隐藏的或简化的,您可以专注于正确定义每个任务的组成以及如何协调它们。

这似乎是非正式的,但正如微软自己在MSDN文档中所说的那样:

  

在.NET Framework 4中,任务是   首选的写作API   多线程,异步和   并行代码。

答案 2 :(得分:0)

waitall机制涉及内核模式对象。我不认为连接机制也是如此。如果有机会,我更愿意加入。

从技术上讲,两者并不相同。 IIRC Join只能在一个线程上运行。 Waitall可以保存多个内核对象的信号。