首页 文章

C#:等待所有线程完成

提问于
浏览
59

我写了'm running into a common pattern in the code that I'm,我需要等待组中的所有线程完成,超时 . 超时应该是所有线程完成所需的时间,因此简单地为每个线程执行thread.Join(timeout)将不起作用,因为可能的超时是超时* numThreads .

现在我做类似以下的事情:

var threadFinishEvents = new List<EventWaitHandle>();

foreach (DataObject data in dataList)
{
    // Create local variables for the thread delegate
    var threadFinish = new EventWaitHandle(false, EventResetMode.ManualReset);
    threadFinishEvents.Add(threadFinish);

    var localData = (DataObject) data.Clone();
    var thread = new Thread(
        delegate()
        {
            DoThreadStuff(localData);
            threadFinish.Set();
        }
    );
    thread.Start();
}

Mutex.WaitAll(threadFinishEvents.ToArray(), timeout);

但是,对于这种事情,似乎应该有一个更简单的习语 .

9 回答

  • 22

    在我的脑海中,你为什么不只是Thread.Join(超时)并从总超时中删除加入所花费的时间?

    // pseudo-c#:
    
    TimeSpan timeout = timeoutPerThread * threads.Count();
    
    foreach (Thread thread in threads)
    {
        DateTime start = DateTime.Now;
    
        if (!thread.Join(timeout))
            throw new TimeoutException();
    
        timeout -= (DateTime.Now - start);
    }
    

    Edit: 代码现在更少伪 . 不明白为什么你会修改答案-2当你修改的答案4完全相同,只是不那么详细 .

  • 1

    这不回答问题(没有超时),但我做了一个非常简单的扩展方法来等待集合的所有线程:

    using System.Collections.Generic;
    using System.Threading;
    namespace Extensions
    {
        public static class ThreadExtension
        {
            public static void WaitAll(this IEnumerable<Thread> threads)
            {
                if(threads!=null)
                {
                    foreach(Thread thread in threads)
                    { thread.Join(); }
                }
            }
        }
    }
    

    然后你只需致电:

    List<Thread> threads=new List<Thread>();
    //Add your threads to this collection
    threads.WaitAll();
    
  • 25

    这可能不适合您,但如果您可以使用.NET的并行扩展,则可以使用 Task 而不是原始线程,然后使用 Task.WaitAll() 等待它们完成 .

  • 1

    我仍然认为使用Join更简单 . 记录预期的完成时间(如现在超时),然后,在循环中,执行

    if(!thread.Join(End-now))
        throw new NotFinishedInTime();
    
  • 9

    使用.NET 4.0,我发现System.Threading.Tasks更容易使用 . 这里's spin-wait loop which works reliably for me. It blocks the main thread until all the tasks complete. There'也是Task.WaitAll,但这对我来说并不总是有效 .

    for (int i = 0; i < N; i++)
            {
                tasks[i] = Task.Factory.StartNew(() =>
                {               
                     DoThreadStuff(localData);
                });
            }
            while (tasks.Any(t => !t.IsCompleted)) { } //spin wait
    
  • 7

    由于问题得到了解决,我将继续发布我的解决方案 .

    using (var finished = new CountdownEvent(1)) 
    { 
      for (DataObject data in dataList) 
      {   
        finished.AddCount();
        var localData = (DataObject)data.Clone(); 
        var thread = new Thread( 
            delegate() 
            {
              try
              {
                DoThreadStuff(localData); 
                threadFinish.Set();
              }
              finally
              {
                finished.Signal();
              }
            } 
        ); 
        thread.Start(); 
      }  
      finished.Signal(); 
      finished.Wait(YOUR_TIMEOUT); 
    }
    
  • 6

    我想弄清楚如何做到这一点,但我无法从谷歌得到任何答案 . 我知道这是一个旧线程,但这是我的解决方案:

    使用以下类:

    class ThreadWaiter
        {
            private int _numThreads = 0;
            private int _spinTime;
    
            public ThreadWaiter(int SpinTime)
            {
                this._spinTime = SpinTime;
            }
    
            public void AddThreads(int numThreads)
            {
                _numThreads += numThreads;
            }
    
            public void RemoveThread()
            {
                if (_numThreads > 0)
                {
                    _numThreads--;
                }
            }
    
            public void Wait()
            {
                while (_numThreads != 0)
                {
                    System.Threading.Thread.Sleep(_spinTime);
                }
            }
        }
    
    • 在执行线程之前调用Addthreads(int numThreads) .

    • 在每个完成后调用RemoveThread() .

    • 在继续之前等待所有线程完成的位置使用Wait()

  • 8

    我读过C#4.0:Herbert Schildt的完整参考书 . 作者使用join来提供解决方案:

    class MyThread
        {
            public int Count;
            public Thread Thrd;
            public MyThread(string name)
            {
                Count = 0;
                Thrd = new Thread(this.Run);
                Thrd.Name = name;
                Thrd.Start();
            }
            // Entry point of thread.
            void Run()
            {
                Console.WriteLine(Thrd.Name + " starting.");
                do
                {
                    Thread.Sleep(500);
                    Console.WriteLine("In " + Thrd.Name +
                    ", Count is " + Count);
                    Count++;
                } while (Count < 10);
                Console.WriteLine(Thrd.Name + " terminating.");
            }
        }
        // Use Join() to wait for threads to end.
        class JoinThreads
        {
            static void Main()
            {
                Console.WriteLine("Main thread starting.");
                // Construct three threads.
                MyThread mt1 = new MyThread("Child #1");
                MyThread mt2 = new MyThread("Child #2");
                MyThread mt3 = new MyThread("Child #3");
                mt1.Thrd.Join();
                Console.WriteLine("Child #1 joined.");
                mt2.Thrd.Join();
                Console.WriteLine("Child #2 joined.");
                mt3.Thrd.Join();
                Console.WriteLine("Child #3 joined.");
                Console.WriteLine("Main thread ending.");
                Console.ReadKey();
            }
        }
    
  • 0

    可能的方法:

    var tasks = dataList
        .Select(data => Task.Factory.StartNew(arg => DoThreadStuff(data), TaskContinuationOptions.LongRunning | TaskContinuationOptions.PreferFairness))
        .ToArray();
    
    var timeout = TimeSpan.FromMinutes(1);
    Task.WaitAll(tasks, timeout);
    

    假设dataList是项目列表,每个项目需要在单独的线程中处理 .

相关问题