2010-02-17 184 views
25

我有一個Windows窗體應用程序,我正在檢查所有串行端口,以查看特定設備是否連接。C#等待多個線程完成

這是我如何分離每個線程。下面的代碼已經脫離了主要的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,但那只是線性處理它們。

+2

嚴格地作爲一個便箋,而不是你詢問它,但是你可以把IsBackground = true放在線程上,以便在你退出應用程序時不會阻塞主線程。 – Patrick 2010-02-17 15:43:14

回答

34
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()); 
+0

這是一個很好且簡單的解決方案。但在我的情況下,System.Threading.Thread.Join()在具有高排他時間值的檢測分析報告中可見。儘管如此,這是一個非常棒的方式。 – Raph 2016-12-22 09:04:02

2

存放在列表中的線程結果後,他們催生和迭代名單 - 在迭代期間調用加入。你仍然線性地加入,但它應該做你想要的。

+0

任何完整的源代碼? – Kiquenet 2014-01-01 09:51:12

14

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


} 
+0

看起來非常棒! – abatishchev 2010-02-17 17:38:46

+2

auto.Set()應該在finally塊中 – 2010-02-17 22:43:33

+3

ManualResetEvent在這裏有什麼意義? – 2013-08-21 21:46:43

3

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

這是不是包含在.NET中作爲CountdownEvent? https://msdn.microsoft.com/en-us/library/system.threading.countdownevent(v=vs.110).aspx – 2015-12-03 00:09:53

5

以最簡單和最安全的方式這樣做是爲了使用CountdownEvent。請參閱Albahari

+0

啊,我不知道如果線程已經終止,Join會返回。感謝您的更正。 – IamIC 2013-07-12 16:24:09