C# 等待多个线程完成
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/2281926/
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
C# Waiting for multiple threads to finish
提问by Andy
I have a windows forms app that I am checking all the serial ports to see if a particular device is connected.
我有一个 Windows 窗体应用程序,我正在检查所有串行端口以查看是否连接了特定设备。
This is how I spin off each thread. The below code is already spun off the main gui thread.
这就是我如何分离每个线程。下面的代码已经从主 gui 线程中分离出来。
foreach (cpsComms.cpsSerial ser in availPorts)
{
    Thread t = new Thread(new ParameterizedThreadStart(lookForValidDev));
    t.Start((object)ser);//start thread and pass it the port
}
I want the next line of code to wait until all the threads have finished.
I've tried using a t.joinin there, but that just processes them linearly.  
我希望下一行代码等到所有线程都完成。我试过t.join在那里使用 a ,但这只是线性处理它们。  
采纳答案by Yuriy Faktorovich
List<Thread> threads = new List<Thread>();
foreach (cpsComms.cpsSerial ser in availPorts)
{
    Thread t = new Thread(new ParameterizedThreadStart(lookForValidDev));
    t.Start((object)ser);//start thread and pass it the port
    threads.Add(t);
}
foreach(var thread in threads)
{
    thread.Join();
}
Edit
编辑
I was looking back at this, and I like the following better
我正在回顾这个,我更喜欢以下内容
availPorts.Select(ser =>
      {
          Thread thread = new Thread(lookForValidDev);
          thread.Start(ser);
          return thread;
      }).ToList().ForEach(t => t.Join());
回答by NG.
Store the Thread results in a list after they were spawned and iterate the list - during iteration call join then. You still join linearly, but it should do what you want.
在产生线程结果并迭代该列表后,将它们存储在一个列表中——然后在迭代调用 join 期间。你仍然线性加入,但它应该做你想做的。
回答by Islam Yahiatene
Use the AutoResetEvent and ManualResetEvent Classes:
使用 AutoResetEvent 和 ManualResetEvent 类:
private ManualResetEvent manual = new ManualResetEvent(false);
void Main(string[] args)
{
    AutoResetEvent[] autos = new AutoResetEvent[availPorts.Count];
    manual.Set();
    for (int i = 0; i < availPorts.Count - 1; i++)
        {
        AutoResetEvent Auto = new AutoResetEvent(false);
        autos[i] = Auto;
        Thread t = new Thread(() => lookForValidDev(Auto, (object)availPorts[i]));
        t.Start();//start thread and pass it the port  
    }
    WaitHandle.WaitAll(autos);
    manual.Reset();
}
void lookForValidDev(AutoResetEvent auto, object obj)
{
    try
    {
         manual.WaitOne();
         // do something with obj 
    }
    catch (Exception)
    {
    }
    finally
    {
        auto.Set();
    }
} 
回答by Kiril
You can use a CountDownLatch:
您可以使用 CountDownLatch:
public class CountDownLatch
{
    private int m_remain;
    private EventWaitHandle m_event;
    public CountDownLatch(int count)
    {
        Reset(count);
    }
    public void Reset(int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException();
        m_remain = count;
        m_event = new ManualResetEvent(false);
        if (m_remain == 0)
        {
            m_event.Set();
        }
    }
    public void Signal()
    {
        // The last thread to signal also sets the event.
        if (Interlocked.Decrement(ref m_remain) == 0)
            m_event.Set();
    }
    public void Wait()
    {
        m_event.WaitOne();
    }
}
Example how to use it:
示例如何使用它:
void StartThreads
{
    CountDownLatch latch = new CountDownLatch(availPorts.Count);
    foreach (cpsComms.cpsSerial ser in availPorts)
    {
        Thread t = new Thread(new ParameterizedThreadStart(lookForValidDev));
        //start thread and pass it the port and the latch
        t.Start((object)new Pair(ser, latch));
    }
    DoSomeWork();
    // wait for all the threads to signal
    latch.Wait();
    DoSomeMoreWork();
}
// In each thread
void NameOfRunMethod
{
    while(running)
    {
        // do work
    }
    // Signal that the thread is done running
    latch.Signal();
}

