C#:等待所有线程完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/263116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 20:23:42  来源:igfitidea点击:

C#: Waiting for all threads to complete

c#multithreading

提问by JSB????

I'm running into a common pattern in the code that I'm writing, where I need to wait for all threads in a group to complete, with a timeout. The timeout is supposed to be the time required for allthreads to complete, so simply doing thread.Join(timeout) for each thread won't work, since the possible timeout is then timeout * numThreads.

我在编写的代码中遇到了一个常见的模式,我需要等待组中的所有线程完成并超时。超时应该是所有线程完成所需的时间,所以简单地为每个线程执行 thread.Join(timeout) 是行不通的,因为可能的超时时间是 timeout * numThreads。

Right now I do something like the following:

现在我做如下事情:

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);

However, it seems like there should be a simpler idiom for this sort of thing.

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

采纳答案by Martin v. L?wis

I still think using Join is simpler. Record the expected completion time (as Now+timeout), then, in a loop, do

我仍然认为使用 Join 更简单。记录预期完成时间(如 Now+timeout),然后循环执行

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

回答by Omer van Kloeten

Off the top of my head, why don't you just Thread.Join(timeout) and remove the time it took to join from the total timeout?

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

// 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:code is now less pseudo. don't understand why you would mod an answer -2 when the answer you modded +4 is exactly the same, only less detailed.

编辑:代码现在不那么伪了。不明白为什么当你修改 +4 的答案完全相同时你会修改答案 -2,只是不太详细。

回答by Jon Norton

This may not be an option for you, but if you can use the Parallel Extension for .NET then you could use Tasks instead of raw threads and then use Task.WaitAll()to wait for them to complete.

这可能不是您的选择,但如果您可以使用 .NET 的并行扩展,那么您可以使用Tasks 代替原始线程,然后用于Task.WaitAll()等待它们完成。

回答by Dylan

I was tying to figure out how to do this but i could not get any answers from google. I know this is an old thread but here was my solution:

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

Use the following class:

使用以下类:

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);
            }
        }
    }
  1. Call Addthreads(int numThreads) before executing a thread(s).
  2. Call RemoveThread() after each one has completed.
  3. Use Wait() at the point that you want to wait for all the threads to complete before continuing
  1. 在执行线程之前调用 Addthreads(int numThreads)。
  2. 在每个完成后调用 RemoveThread()。
  3. 在继续之前要等待所有线程完成的地方使用 Wait()

回答by Brian Gideon

Since the question got bumped I will go ahead and post my solution.

由于问题被提出,我将继续发布我的解决方案。

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); 
} 

回答by T. Webster

With .NET 4.0 I find System.Threading.Tasksa lot easier to work with. Here's spin-wait loop which works reliably for me. It blocks the main thread until all the tasks complete. There's also Task.WaitAll, but that hasn't always worked for me.

使用 .NET 4.0,我发现System.Threading.Tasks更容易使用。这是对我来说可靠的旋转等待循环。它阻塞主线程,直到所有任务完成。还有Task.WaitAll,但这并不总是对我有用

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

回答by Alex Aza

Possible solution:

可能的解决方案:

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);

Assuming dataList is the list of items and each item needs to be processed in a separate thread.

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

回答by Bùi C?ng Giao

I read the book C# 4.0: The Complete Reference of Herbert Schildt. The author use join to give a solution :

我读了 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();
        }
    }

回答by Vincent

This doesn't answer the question (no timeout), but I've made a very simple extension method to wait all threads of a collection:

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

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(); }
            }
        }
    }
}

Then you simply call:

然后你只需调用:

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