3

This is my first real attempt at using multithreading, I want to know how I can tell when all of my tasks groups are done running:

for (int i = 0; i < taskGroups.Count(); i++) {
    ThreadStart t = delegate { RunThread(taskGroups[i]); };
    new Thread(t).Start();
}
if(allThreadsComplete){ //???

}

Any help would be much appreciated

Addendum:

ThreadStart[] threads = new ThreadStart[taskGroups.Count()];
for (int i = 0; i < taskGroups.Count(); i++) {
    threads[i] = new ThreadStart[]
    threads[i] = delegate { RunThread(taskGroups[i]); };
    new Thread(t).Start();
}
bool threadsComplete = false;
while(!threadsComplete){
    for(int i=0;i<taskGroups.Count();i++){
        if(threads[i].State == complete)
        threadsComplete = true;
    }
}
sooprise
  • 22,657
  • 67
  • 188
  • 276
  • 2
    Your `i` variable is shared by all of the threads. – SLaks Mar 13 '11 at 14:32
  • http://msdn.microsoft.com/en-us/library/system.threading.thread.threadstate.aspx – Jaroslav Jandek Mar 13 '11 at 14:35
  • In case it's not clear from what Slaks has commented - it would be possible for two (or more) of your threads to start and observe the same value of `i`, when calling `RunThread` - almost certainly something you do not want. – Damien_The_Unbeliever Mar 13 '11 at 14:35
  • 1
    In addition, if you're learning for future dev work, it would be better to learn to do multi-threading using Tasks and the Task Parallel Library - it's a more up to date set of threading primitives for .NET. – Damien_The_Unbeliever Mar 13 '11 at 14:37
  • re the shared i, should I create all of the tasks in one loop, the start all of the tasks in a separate loop? – sooprise Mar 13 '11 at 14:37
  • @sooprise - if you did that, you'd *guarantee* that they'd all see the same value for `i` - and it would probably be `== taskGroups.Count`, so out of range for the array – Damien_The_Unbeliever Mar 13 '11 at 14:40
  • Damien, I just encountered this taskGroup.Count error and I don't know how to fix it. Any suggestions? I'm totally lost... – sooprise Mar 13 '11 at 15:37

6 Answers6

4

You need to store all your threads, and then call Thread.Join().

Something like this:

List<Thread> threads = new List<Thread>();
for (int i = 0; i < taskGroups.Count(); i++) {
   int temp = i; //This fixes the issue with i being shared
   Thread thread = new Thread(() => RunThread(taskGroups[temp]));
   threads.Add(thread);
   thread.Start();
}

foreach (var thread in threads) {
    thread.Join();
}
jonathanpeppers
  • 26,115
  • 21
  • 99
  • 182
  • inside of your for loop, how do I assign a method with a parameter to a specific thread? like, thread.doWork=someMethod(aParameter) – sooprise Mar 13 '11 at 14:49
  • Thread thread = new Thread(() => someMethod(aParameter)); If it complains about your delegate type, cast to a (ThreadStart) inside the Thread constructor. – jonathanpeppers Mar 13 '11 at 14:52
  • I read the guy's comments above. Store "i" in a local variable inside your loop to fix your issue. I'll update my answer shortly. – jonathanpeppers Mar 13 '11 at 14:53
  • Jonathan, Thanks! that temp variable fixed it up! – sooprise Mar 13 '11 at 15:52
1

If you're using 3.5 then you can write your own CountdownEvent, if you're using 4.0 then you can use the built in CountdownEvent to do something like this:

CountdownEvent = new CountdownEvent(taskGroups.Count());

for (int i = 0; i < taskGroups.Count(); i++) 
{
    int item = i; // copy i locally
    ThreadStart t = delegate 
    { 
        RunThread(taskGroups[item]); 
        latch.Signal();
    };
    new Thread(t).Start();
}

latch.Wait();

The latch.Wait() will cause your code to block until the threads have all finished. Furthermore, you might want to change the way you start your thread a bit:

CountdownEvent = new CountdownEvent(taskGroups.Count());

for (int i = 0; i < taskGroups.Count(); i++) 
{
    int item = i; // copy i locally
    Thread t = new Thread(()=>
    { 
        RunThread(taskGroups[item]); 
        latch.Signal();
    });
    t.IsBackground = true;
    t.Start();
}

latch.Wait();

Note that I'm setting the thread to background: this your application from hanging when exit and not all threads have finished (i.e. prevents ghost or daemon threads).

Community
  • 1
  • 1
Kiril
  • 39,672
  • 31
  • 167
  • 226
0

You can check the ThreadState property of each Thread object.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
0

You can use Thread.Join to make sure that each individual thread has finished running.

Dror Helper
  • 30,292
  • 15
  • 80
  • 129
0

You can add public static integer field to the main thread, in each child thread increase it by one when it's completed then in the main thread wait (in a loop) until that variable is equal to the taskGroups.Count().

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
0

First of all consider switching to the new asynchronous pattern using Task.

Anyway if you want to wait for all your threads you can call Thread.Join:

var threads = new List<Thread>();    
for (int i = 0; i < taskGroups.Count(); i++) {
    ThreadStart t = delegate { RunThread(taskGroups[i]); };
    var thread = new Thread(t);
    threads.Add(thread);
    thread.Start();
}

threads.ForEach(a => a.Join());

Remember that you can also pass a timeout parameter that will wait until the thread finishes only if it doesn't takes more than the time you passed in.

as-cii
  • 12,819
  • 4
  • 41
  • 43