2010-02-17 28 views
25

Tôi có một ứng dụng biểu mẫu cửa sổ mà tôi đang kiểm tra tất cả các cổng nối tiếp để xem một thiết bị cụ thể có được kết nối không.C# Đang đợi nhiều chủ đề kết thúc

Đây là cách tôi quay từng chuỗi. Đoạn mã dưới đây đã được tách ra khỏi sợi gui chính.

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ôi muốn dòng mã tiếp theo đợi cho đến khi tất cả các chuỗi đã kết thúc. Tôi đã thử sử dụng một số t.join trong đó, nhưng điều đó chỉ xử lý chúng tuyến tính.

+2

Đúng như một lưu ý phụ chứ không phải là bạn đã hỏi về nó, nhưng bạn có thể đặt IsBackground = true trên chuỗi để không chặn nó chặn chuỗi chính nếu bạn thoát khỏi ứng dụng. – Patrick

Trả lời

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

Sửa

Tôi đã nhìn lại lúc này, và tôi thích như sau tốt hơn

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

Đây là giải pháp tốt và đơn giản. Nhưng trong trường hợp của tôi System.Threading.Thread.Join() có thể nhìn thấy trong báo cáo cấu hình thiết bị với giá trị thời gian độc quyền cao. Mặc dù vậy, đó là một cách thực sự tuyệt vời. – Raph

2

Store kết quả Chủ đề trong một danh sách sau khi họ đã sinh ra và lặp danh sách - trong khi gọi tham gia lặp lại rồi. Bạn vẫn tham gia tuyến tính, nhưng nó sẽ làm những gì bạn muốn.

+0

bất kỳ mã nguồn đầy đủ nào về nó? – Kiquenet

14

Sử dụng AutoResetEvent và ManualResetEvent Lớp học:

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

Trông tuyệt vời! – abatishchev

+2

auto.Set() phải ở trong khối cuối cùng –

+3

Điểm của ManualResetEvent ở đây là gì? –

3

Bạn có thể sử dụng một 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(); 
    } 
} 

Ví dụ làm thế nào để sử dụng nó:

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

Không được bao gồm trong .NET dưới dạng CountdownEvent? https://msdn.microsoft.com/en-us/library/system.threading.countdownevent(v=vs.110).aspx –

5

Cách đơn giản nhất và an toàn nhất để làm điều này là sử dụng một CountdownEvent. Xem Albahari.

+0

Ah, tôi không biết rằng nếu chuỗi đã chấm dứt, Tham gia sẽ trở lại. Cảm ơn vì sự đúng đắn của bạn. – IamIC

Các vấn đề liên quan