Home > OS >  How to wait for threads to finish when creating them using a for loop
How to wait for threads to finish when creating them using a for loop

Time:10-12

If I used this code to create threads, how can I wait for all of these threads to complete before proceeding with the rest of the code? Or is there a different way to do this?

for(int i = 0; i < 25; i   )
{             
   Program x = new Program(); // Make temporary
   Thread myThread = new Thread(() => x.doSomething(someParameter));
   myThread.Start();
}

I want to avoid making a big chunk of code for initializng, creating and joining threads.

Thread myThread1 = new Thread(() => x.doSomething(someParameter));
myThread1.Start();

Thread myThread2 = new Thread(() => x.doSomething(someParameter));
myThread2.Start();

Thread myThread3 = new Thread(() => x.doSomething(someParameter));
myThread3.Start();

myThread1.Join();
myThread2.Join();
myThread3.Join();

This code works but my goal is to avoid doing this 50-100 / n times depending on how many threads I need.

CodePudding user response:

The simplest solution is probably to put the threads into an array, then iterate over those threads to wait for all of them.

int numThreads = 25;
var threads = new Thread[numThreads];
for (int i = 0; i < numThreads; i  )
{
    Program x = new Program();
    Thread myThread = new Thread(() => x.doSomething(someParameter));
    myThread.Start();
    threads[i] = myThread;
}

foreach (var thread in threads)
{
    thread.Join();
}

That said, I'd recommend looking into whether tasks would work better than threads: threads are a bit more ... brute-force, though there are reasons to use them. I'd also look into the Parallel class, which lets you control the level of parallelism, if your threads can be run there (they probably can, but there may be reasons not to do so). In that case, you'd just do something like

Parallel.For(0, 25, i => { new Program().doSomething(someParameter); });    

... note that i is available inside the curly braces as the loop index; you could do something like new Program().doSomething(i); to pass a different parameter to each invocation of doSomething.

CodePudding user response:

An even better way is to use the Task Parallel Library (TPL).

int numTasks = 25;
var tasks = new Task[numTasks];
for (int i = 0; i < numTasks; i  )
{
    tasks[i] = Task.Run(() => new Program().doSomething(someParameter));
}
Task.WaitAll(tasks);

Starting a Thread consumes 1MB of RAM as is resource intensive. Tasks are managed better by the framework.

And, again, even better, you could do this:

var tasks =
    Enumerable
        .Range(0, numTasks)
        .Select(i => Task.Run(() => new Program().doSomething(someParameter)))
        .ToArray();
Task.WaitAll(tasks);

And possibly better again, you can await the whole lot:

async Task Main()
{
    var someParameter = new object();
    int numTasks = 25;
    var tasks =
        Enumerable
            .Range(0, numTasks)
            .Select(i => Task.Run(() => new Program().doSomething(someParameter)))
            .ToArray();
    await Task.WhenAll(tasks);
}
  • Related