42

I have a windows forms app that I am checking all the serial ports to see if a particular device is connected.

This is how I spin off each thread. The below code is already spun off the main gui 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
}

I want the next line of code to wait until all the threads have finished. I've tried using a t.join in there, but that just processes them linearly.

1
  • 2
    Strictly as a side note and not that you asked about it, but you can put IsBackground = true on the thread to not have it block the main thread if you exit the application. Commented Feb 17, 2010 at 15:43

5 Answers 5

49
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());
Sign up to request clarification or add additional context in comments.

1 Comment

This is good and simple solution. But in my case System.Threading.Thread.Join() is visible in instrumentation profiling report with high exclusive time value. Despite of this, that is a really great way.
16

Use the AutoResetEvent and ManualResetEvent Classes:

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


} 

1 Comment

auto.Set() should be in a finally block
10

The simplest and safest way to do this is to use a CountdownEvent. See Albahari.

1 Comment

Ah, I didn't know that if the thread has terminated, the Join would return. Thanks for the correction.
3

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.

Comments

2

You can use a 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();
}

1 Comment

Isn't this included in .NET as CountdownEvent? msdn.microsoft.com/en-us/library/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.