创建多个线程并等待所有线程完成

时间:2022-05-01 12:18:16

How to Create multiple threads and wait all of them to complete?

如何创建多个线程并等待所有线程完成?

8 个解决方案

#1


76  

It depends which version of the .NET Framework you are using. .NET 4.0 made thread management a whole lot easier using Tasks:

这取决于您使用的.NET Framework版本。使用Tasks,.NET 4.0使线程管理变得更加容易:

class Program
{
    static void Main(string[] args)
    {
        Task task1 = Task.Factory.StartNew(() => doStuff());
        Task task2 = Task.Factory.StartNew(() => doStuff());
        Task task3 = Task.Factory.StartNew(() => doStuff());

        Task.WaitAll(task1, task2, task3);
                Console.WriteLine("All threads complete");
    }

    static void doStuff()
    {
        //do stuff here
    }
}

In previous versions of .NET you could use the BackgroundWorker object, use ThreadPool.QueueUserWorkItem(), or create your threads manually and use Thread.Join() to wait for them to complete:

在以前的.NET版本中,您可以使用BackgroundWorker对象,使用ThreadPool.QueueUserWorkItem(),或手动创建线程并使用Thread.Join()等待它们完成:

static void Main(string[] args)
{
    Thread t1 = new Thread(doStuff);
    t1.Start();

    Thread t2 = new Thread(doStuff);
    t2.Start();

    Thread t3 = new Thread(doStuff);
    t3.Start();

    t1.Join();
    t2.Join();
    t3.Join();

    Console.WriteLine("All threads complete");
}

#2


23  

I think you need WaitHandler.WaitAll. Here is an example:

我想你需要WaitHandler.WaitAll。这是一个例子:

public static void Main(string[] args)
{
    int numOfThreads = 10;
    WaitHandle[] waitHandles = new WaitHandle[numOfThreads];

    for (int i = 0; i < numOfThreads; i++)
    {
        var j = i;
        // Or you can use AutoResetEvent/ManualResetEvent
        var handle = new EventWaitHandle(false, EventResetMode.ManualReset);
        var thread = new Thread(() =>
                                {
                                    Thread.Sleep(j * 1000);
                                    Console.WriteLine("Thread{0} exits", j);
                                    handle.Set();
                                });
        waitHandles[j] = handle;
        thread.Start();
    }
    WaitHandle.WaitAll(waitHandles);
    Console.WriteLine("Main thread exits");
    Console.Read();
}

EDIT FCL has a few more convenient functions.

编辑FCL有一些更方便的功能。

(1) Task.WaitAll, as well as its overloads, when you want to do some tasks in parallel (and with no return values).

(1)当你想并行执行某些任务(并且没有返回值)时,Task.WaitAll及其重载。

var tasks = new[]
{
    Task.Factory.StartNew(() => DoSomething1()),
    Task.Factory.StartNew(() => DoSomething2()),
    Task.Factory.StartNew(() => DoSomething3())
};    
Task.WaitAll(tasks);

(2) Task.WhenAll when you want to do some tasks with return values, it performs the operations and puts the results in an array. It's thread-safe, you don't need to using a thread-safe container and implement the add operation yourself.

(2)Task.WhenAll当你想用返回值做一些任务时,它执行操作并将结果放在一个数组中。它是线程安全的,您不需要使用线程安全的容器并自己实现添加操作。

var tasks = new[]
{
    Task.Factory.StartNew(() => GetSomething1()),
    Task.Factory.StartNew(() => GetSomething2()),
    Task.Factory.StartNew(() => GetSomething3())
};    
var things = Task.WhenAll(tasks);

#3


4  

In .Net 4.0, you can use the Task Parallel Library.

在.Net 4.0中,您可以使用任务并行库。

In earlier versions, you can create a list of Thread objects in a loop, calling Start on each one, then make another loop and call Join on each one.

在早期版本中,您可以在循环中创建一个Thread对象列表,在每个对象上调用Start,然后再创建一个循环并在每个循环上调用Join。

#4


4  

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

#5


0  

Don't know if there is a better way, but following describes how I did it with a counter and background worker thread.

不知道是否有更好的方法,但下面描述了我是如何使用计数器和后台工作线程完成的。

private object _lock=new object();
private int _runningThreads = 0;

private int Counter{
    get{
           lock(_lock) 
               return _runningThreads;
    }
    set{ 
           lock(_lock) 
               _runningThreads = value;
    }
}

Now whenever you create a worker thread, increment the counter:

现在,无论何时创建工作线程,都要递增计数器:

var t=new BackgroundWorker();
//ADD RunWorkerCompleted HANDLER
//START THREAD
Counter++;

In work completed, decrement the counter:

在完成的工作中,减少计数器:

private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Counter--;
}

Now you can check for the counter anytime to see if any thread is running:

现在,您可以随时检查计数器以查看是否有任何线程正在运行:

if(Couonter>0){
    //SOME THREAD IS YET TO FINISH.
}

#6


0  

Most proposed answers don't take into account a time-out interval, which is very important to prevent a possible deadlock. Next is my sample code. (Note that I'm primarily a Win32 developer, and that's how I'd do it there.)

大多数建议的答案没有考虑超时间隔,这对于防止可能的死锁非常重要。接下来是我的示例代码。 (请注意,我主要是Win32开发人员,我就是这样做的。)

//'arrRunningThreads' = List<Thread>

//Wait for all threads
const int knmsMaxWait = 3 * 1000;           //3 sec timeout
int nmsBeginTicks = Environment.TickCount;
foreach(Thread thrd in arrRunningThreads)
{
    //See time left
    int nmsElapsed = Environment.TickCount - nmsBeginTicks;
    int nmsRemain = knmsMaxWait - nmsElapsed;
    if(nmsRemain < 0)
        nmsRemain = 0;

    //Then wait for thread to exit
    if(!thrd.Join(nmsRemain))
    {
        //It didn't exit in time, terminate it
        thrd.Abort();

        //Issue a debugger warning
        Debug.Assert(false, "Terminated thread");
    }
}

#7


0  

If you don't want to use Task class (for instance in .NET 3.5) you can just start all your threads then add them in list and join them in foreach loop.

如果您不想使用Task类(例如在.NET 3.5中),您可以启动所有线程,然后将它们添加到列表中并将它们连接到foreach循环中。

Example:

例:

List<Thread> threads = new List<Thread>();


// Start threads
for(int i = 0; i<10; i++)
{
    int tmp = i; // copy value for closure
    Thread t = new Thread(() => Console.WriteLine(tmp));
    t.Start;
    threads.Add(t);
}

// Await threads
foreach(Thread thread in threads)
{
    thread.Join();
}

#8


0  

In my case I could not instantiate my objects on the the thread pool with Task.Run() or Task.Factory.StartNew(). They would not synchronize my long running delegates correctly. I needed the delegates to run asynchronously, pausing my main thread for their collective completion. The Thread.Join() would not work since I wanted to wait for collective completion in the middle of the parent thread, not at the end. With the Task.Run() or Task.Factory.StartNew() either all the child threads blocked each other or the parent thread would not be blocked, ... I couldn't figure out how to go with async delegates because of the re-serialization of the await syntax.

在我的情况下,我无法使用Task.Run()或Task.Factory.StartNew()在线程池上实例化我的对象。他们不会正确地同步我长时间运行的代理。我需要代理以异步方式运行,暂停我的主线程以便集体完成。 Thread.Join()无法工作,因为我想在父线程的中间等待集体完成,而不是在最后。使用Task.Run()或Task.Factory.StartNew()要么所有子线程相互阻塞,要么父线程不会被阻塞,...我无法弄清楚如何使用异步委托,因为重新序列化await语法。

Here is my solution using Threads instead of Tasks:

这是我的解决方案使用线程而不是任务:

using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.ManualReset))
{
  int outdex = mediaServerMinConnections - 1;
  for (int i = 0; i < mediaServerMinConnections; i++)
  {
    new Thread(() =>
    {
      sshPool.Enqueue(new SshHandler());
      if (Interlocked.Decrement(ref outdex) < 1)
        wh.Set();
    }).Start();
  }
  wh.WaitOne();
}

(Apologies for the dense coding style.)

(为密集编码风格道歉。)

#1


76  

It depends which version of the .NET Framework you are using. .NET 4.0 made thread management a whole lot easier using Tasks:

这取决于您使用的.NET Framework版本。使用Tasks,.NET 4.0使线程管理变得更加容易:

class Program
{
    static void Main(string[] args)
    {
        Task task1 = Task.Factory.StartNew(() => doStuff());
        Task task2 = Task.Factory.StartNew(() => doStuff());
        Task task3 = Task.Factory.StartNew(() => doStuff());

        Task.WaitAll(task1, task2, task3);
                Console.WriteLine("All threads complete");
    }

    static void doStuff()
    {
        //do stuff here
    }
}

In previous versions of .NET you could use the BackgroundWorker object, use ThreadPool.QueueUserWorkItem(), or create your threads manually and use Thread.Join() to wait for them to complete:

在以前的.NET版本中,您可以使用BackgroundWorker对象,使用ThreadPool.QueueUserWorkItem(),或手动创建线程并使用Thread.Join()等待它们完成:

static void Main(string[] args)
{
    Thread t1 = new Thread(doStuff);
    t1.Start();

    Thread t2 = new Thread(doStuff);
    t2.Start();

    Thread t3 = new Thread(doStuff);
    t3.Start();

    t1.Join();
    t2.Join();
    t3.Join();

    Console.WriteLine("All threads complete");
}

#2


23  

I think you need WaitHandler.WaitAll. Here is an example:

我想你需要WaitHandler.WaitAll。这是一个例子:

public static void Main(string[] args)
{
    int numOfThreads = 10;
    WaitHandle[] waitHandles = new WaitHandle[numOfThreads];

    for (int i = 0; i < numOfThreads; i++)
    {
        var j = i;
        // Or you can use AutoResetEvent/ManualResetEvent
        var handle = new EventWaitHandle(false, EventResetMode.ManualReset);
        var thread = new Thread(() =>
                                {
                                    Thread.Sleep(j * 1000);
                                    Console.WriteLine("Thread{0} exits", j);
                                    handle.Set();
                                });
        waitHandles[j] = handle;
        thread.Start();
    }
    WaitHandle.WaitAll(waitHandles);
    Console.WriteLine("Main thread exits");
    Console.Read();
}

EDIT FCL has a few more convenient functions.

编辑FCL有一些更方便的功能。

(1) Task.WaitAll, as well as its overloads, when you want to do some tasks in parallel (and with no return values).

(1)当你想并行执行某些任务(并且没有返回值)时,Task.WaitAll及其重载。

var tasks = new[]
{
    Task.Factory.StartNew(() => DoSomething1()),
    Task.Factory.StartNew(() => DoSomething2()),
    Task.Factory.StartNew(() => DoSomething3())
};    
Task.WaitAll(tasks);

(2) Task.WhenAll when you want to do some tasks with return values, it performs the operations and puts the results in an array. It's thread-safe, you don't need to using a thread-safe container and implement the add operation yourself.

(2)Task.WhenAll当你想用返回值做一些任务时,它执行操作并将结果放在一个数组中。它是线程安全的,您不需要使用线程安全的容器并自己实现添加操作。

var tasks = new[]
{
    Task.Factory.StartNew(() => GetSomething1()),
    Task.Factory.StartNew(() => GetSomething2()),
    Task.Factory.StartNew(() => GetSomething3())
};    
var things = Task.WhenAll(tasks);

#3


4  

In .Net 4.0, you can use the Task Parallel Library.

在.Net 4.0中,您可以使用任务并行库。

In earlier versions, you can create a list of Thread objects in a loop, calling Start on each one, then make another loop and call Join on each one.

在早期版本中,您可以在循环中创建一个Thread对象列表,在每个对象上调用Start,然后再创建一个循环并在每个循环上调用Join。

#4


4  

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

#5


0  

Don't know if there is a better way, but following describes how I did it with a counter and background worker thread.

不知道是否有更好的方法,但下面描述了我是如何使用计数器和后台工作线程完成的。

private object _lock=new object();
private int _runningThreads = 0;

private int Counter{
    get{
           lock(_lock) 
               return _runningThreads;
    }
    set{ 
           lock(_lock) 
               _runningThreads = value;
    }
}

Now whenever you create a worker thread, increment the counter:

现在,无论何时创建工作线程,都要递增计数器:

var t=new BackgroundWorker();
//ADD RunWorkerCompleted HANDLER
//START THREAD
Counter++;

In work completed, decrement the counter:

在完成的工作中,减少计数器:

private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Counter--;
}

Now you can check for the counter anytime to see if any thread is running:

现在,您可以随时检查计数器以查看是否有任何线程正在运行:

if(Couonter>0){
    //SOME THREAD IS YET TO FINISH.
}

#6


0  

Most proposed answers don't take into account a time-out interval, which is very important to prevent a possible deadlock. Next is my sample code. (Note that I'm primarily a Win32 developer, and that's how I'd do it there.)

大多数建议的答案没有考虑超时间隔,这对于防止可能的死锁非常重要。接下来是我的示例代码。 (请注意,我主要是Win32开发人员,我就是这样做的。)

//'arrRunningThreads' = List<Thread>

//Wait for all threads
const int knmsMaxWait = 3 * 1000;           //3 sec timeout
int nmsBeginTicks = Environment.TickCount;
foreach(Thread thrd in arrRunningThreads)
{
    //See time left
    int nmsElapsed = Environment.TickCount - nmsBeginTicks;
    int nmsRemain = knmsMaxWait - nmsElapsed;
    if(nmsRemain < 0)
        nmsRemain = 0;

    //Then wait for thread to exit
    if(!thrd.Join(nmsRemain))
    {
        //It didn't exit in time, terminate it
        thrd.Abort();

        //Issue a debugger warning
        Debug.Assert(false, "Terminated thread");
    }
}

#7


0  

If you don't want to use Task class (for instance in .NET 3.5) you can just start all your threads then add them in list and join them in foreach loop.

如果您不想使用Task类(例如在.NET 3.5中),您可以启动所有线程,然后将它们添加到列表中并将它们连接到foreach循环中。

Example:

例:

List<Thread> threads = new List<Thread>();


// Start threads
for(int i = 0; i<10; i++)
{
    int tmp = i; // copy value for closure
    Thread t = new Thread(() => Console.WriteLine(tmp));
    t.Start;
    threads.Add(t);
}

// Await threads
foreach(Thread thread in threads)
{
    thread.Join();
}

#8


0  

In my case I could not instantiate my objects on the the thread pool with Task.Run() or Task.Factory.StartNew(). They would not synchronize my long running delegates correctly. I needed the delegates to run asynchronously, pausing my main thread for their collective completion. The Thread.Join() would not work since I wanted to wait for collective completion in the middle of the parent thread, not at the end. With the Task.Run() or Task.Factory.StartNew() either all the child threads blocked each other or the parent thread would not be blocked, ... I couldn't figure out how to go with async delegates because of the re-serialization of the await syntax.

在我的情况下,我无法使用Task.Run()或Task.Factory.StartNew()在线程池上实例化我的对象。他们不会正确地同步我长时间运行的代理。我需要代理以异步方式运行,暂停我的主线程以便集体完成。 Thread.Join()无法工作,因为我想在父线程的中间等待集体完成,而不是在最后。使用Task.Run()或Task.Factory.StartNew()要么所有子线程相互阻塞,要么父线程不会被阻塞,...我无法弄清楚如何使用异步委托,因为重新序列化await语法。

Here is my solution using Threads instead of Tasks:

这是我的解决方案使用线程而不是任务:

using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.ManualReset))
{
  int outdex = mediaServerMinConnections - 1;
  for (int i = 0; i < mediaServerMinConnections; i++)
  {
    new Thread(() =>
    {
      sshPool.Enqueue(new SshHandler());
      if (Interlocked.Decrement(ref outdex) < 1)
        wh.Set();
    }).Start();
  }
  wh.WaitOne();
}

(Apologies for the dense coding style.)

(为密集编码风格道歉。)