【问题标题】:C#, how do I know when all my theads have finished?C#,我怎么知道我的所有主题何时完成?
【发布时间】:2011-10-07 17:07:37
【问题描述】:

我有一个“线程”类,它会抛出执行进程的线程。线程在线程类中有一个回调方法,当它们完成时会被调用。我的问题是我如何知道线程器抛出的所有线程何时完成?

【问题讨论】:

标签: c# multithreading callback


【解决方案1】:

如果您对已启动的线程数进行计数,您可以简单地在线程启动时增加计数,并在线程结束时减少计数。

然后当计数达到零时,您就知道所有线程都已完成。

在处理短期线程时需要小心,以确保允许计数器在递减之前递增。需要使用某种锁定或Interlocked.IncrementDecrement 来修改计数器变量。 Source

【讨论】:

  • 这就是我想要的。对不起,我的大脑今天早上不工作:)
  • 如果一个线程是短暂的,在所有线程启动之前计数可能会达到0。
  • 修改计数器变量时务必使用Interlocked.Increment/Decrement...
  • 如果线程寿命很短,甚至出现意外线程优先级,这将失败。
  • 好吧,我有一个队列,其中包含我要启动的文件,所以如果队列为空 && 线程数为 0,我就这样做了,然后显示总数。这应该足够正确了吗?
【解决方案2】:

您可以为活动线程数保留一个简单的计数器。或者,您可以让线程在开始工作之前在集合中注册(添加)自己,并在完成后删除。

【讨论】:

    【解决方案3】:

    计数有效,但实现起来可能比您想象的要难...确保在线程内的 finally 块中进行递减并同步 (lock) 对计数器的访问(我知道,它应该是原子的,但无论如何......)。

    如果您只创建一些线程并拥有线程实例,您也可以 Thread.Join 每个实例。即使在您调用 join 之前线程已经终止(但仍然在清理实例之前),这仍然有效。

    所以:

    foreach( Thread thread in myThreads)
    {
       thread.join();
    }
    

    一旦完成,您就确定所有线程都已完成。

    马里奥

    【讨论】:

      【解决方案4】:

      最简单的方法是,如果您事先知道将要运行的线程数,则可以在回调函数中使用计数器。

      如果您不知道线程数,那么您需要一些“处理结束”指示器来设置布尔值以及创建和结束线程的计数器。

      如果您不知道要创建的线程数,那么简单的两个计数器的想法就行不通(如果第一个线程在任何其他线程创建之前开始和结束,它会错误地认为它是最后一个)。

      【讨论】:

        【解决方案5】:

        在线程线程中检查每个线程的状态。如果所有线程都停止(或中止),你知道你可以结束主线程。

        【讨论】:

          【解决方案6】:

          您可以使用WaitHandles。如果您使用 BeginInvoke/EndInvoke 来控制您的线程,这将变得更加有吸引力(因为 IAsyncResult 带有 WaitHandle)。请记住在WaitAll 调用期间不要超过操作系统限制超过 64 个项目。这里有一个扩展方法可以让这个过程更简单:

          static class ThreadingExtensions
          {
              // Possible:
              // [ThreadStatic]
              // private static List<WaitHandle> PerThreadWaitList;
              public const int MaxHandlesPerWait = 64;
          
              public static void WaitAll<T>(this IEnumerable<T> handles, int millisecondsTimeout, int estimatedCount)
                  where T : WaitHandle
              {
                  // Possible:
                  // var currentSet = PerThreadWaitList ?? (PerThreadWaitList = new List<WaitHandle>(estimatedCount));
                  var currentSet = new List<WaitHandle>(Math.Min(estimatedCount, MaxHandlesPerWait));
                  var timeoutEnd = Environment.TickCount + millisecondsTimeout;
                  int timeout;
          
                  // Wait for items in groups of 64.
                  foreach (var item in handles)
                  {
                      currentSet.Add(item);
                      if (currentSet.Count == MaxHandlesPerWait)
                      {
                          timeout = Timeout.Infinite;
                          if (millisecondsTimeout >= 0)
                          {
                              timeout = timeoutEnd - Environment.TickCount;
                              if (timeout < 0)
                                  throw new TimeoutException();
                          }
                          WaitHandle.WaitAll(currentSet.ToArray(), timeout);
                          currentSet.Clear();
                      }
                  }
          
                  // Do the last set.
                  if (currentSet.Count > 0)
                  {
                      timeout = Timeout.Infinite;
                      if (millisecondsTimeout >= 0)
                      {
                          timeout = timeoutEnd - Environment.TickCount;
                          if (timeout < 0)
                              timeout = 0;
                      }
                      WaitHandle.WaitAll(currentSet.ToArray(), timeout);
                      currentSet.Clear();
                  }
              }
          }
          

          还有一个用法示例。

          var results = new List<IAsyncResult>();
          // Call delegates, e.g.
          // results.Add(Foo.BeginInvoke(OnEndInvokeFoo));
          results.Select(x => x.AsyncWaitHandle).WaitAll(Timeout.Infinite, results.Count);
          

          【讨论】:

            【解决方案7】:

            线程计数器的示例代码

            long counter = 0;
            
            void ThreadEntryPoint()
            {
              try
              {
                ...
                //
              }
              finally
              {
                // Decrement counter
                Interlocked.Decrement(ref counter);
              }
            }
            
            void MainThread()
            {
              // Start worers
              for(...)
              {
                // Increment threads couter
                Interlocked.Increment(ref counter);
                ((Action)ThreadEntryPoint).BeginInvoke(null, null);
              }
            
              // Wait until counter is equal to 0
              while(Interlocked.Read(ref counter) != 0)
              {
                Thread.Sleep(0);
              }
            }
            

            【讨论】:

              猜你喜欢
              • 2017-01-31
              • 1970-01-01
              • 1970-01-01
              • 2018-07-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多