【问题标题】:C# Waiting for multiple threads to finishC#等待多个线程完成
【发布时间】:2010-02-17 15:28:57
【问题描述】:

我有一个 Windows 窗体应用程序,我正在检查所有串行端口以查看是否连接了特定设备。

这就是我分离每个线程的方式。下面的代码已经从主 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
}

我希望下一行代码等到所有线程都完成。 我试过在那里使用t.join,但这只是线性处理它们。

【问题讨论】:

  • 严格作为旁注,而不是您询问它,但是您可以将 IsBackground = true 放在线程上,以免在退出应用程序时阻塞主线程。

标签: c# multithreading


【解决方案1】:
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();
}

编辑

我在回顾这个,我更喜欢下面这个

availPorts.Select(ser =>
      {
          Thread thread = new Thread(lookForValidDev);
          thread.Start(ser);
          return thread;
      }).ToList().ForEach(t => t.Join());

【讨论】:

  • 这是一个简单又好用的解决方案。但在我的情况下, System.Threading.Thread.Join() 在具有高独占时间价值的仪器分析报告中可见。尽管如此,这确实是一个很棒的方法。
【解决方案2】:

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


} 

【讨论】:

  • auto.Set() 应该在 finally 块中
【解决方案3】:

最简单、最安全的方法是使用 CountdownEvent。见Albahari

【讨论】:

  • 啊,我不知道如果线程已经终止,Join 会返回。谢谢指正。
【解决方案4】:

您可以使用 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();
    }
}

使用示例:

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

【讨论】:

【解决方案5】:

在线程结果生成后将它们存储在一个列表中并迭代该列表 - 然后在迭代期间调用加入。你仍然线性加入,但它应该做你想做的事。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-18
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-19
    • 1970-01-01
    相关资源
    最近更新 更多