Click here to Skip to main content
13,894,773 members
Rate this:
 
Please Sign up or sign in to vote.
See more:
I have created threads dynamically.

static void Main(string[] args)
{
    int ThreadCount =Convert.ToInt32ConfigurationManager.AppSettings["Threads"]);
    List<Thread> th = new List<Thread>();
    for (int i = 0; i < ThreadCount; i++)
    {
       Thread t = new Thread(print);
       th.Add(t);
    }
    foreach (Thread t in th)
    {
        t.Start();
    }
}
public void print()
{
    console.writeline("123");
}


I want to know when this threads will complete. On completion of these threads i want to print a message of "DONE"

How can i do this.
Posted
Updated 29-Oct-12 22:36pm
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 3

There is no built in way to do this - you could poll the IsAlive property on a regular basis, but that's a nasty solution.

A better solution is to create an event to which you subscribe - and signal it at the end of the thread method. You can then check the live threads and report when all are complete.

MSDN has an example of doing just that: http://msdn.microsoft.com/en-us/library/aa645739%28VS.71%29.aspx[^]

The other solution is to use a BackgroundWorker instead of a Thread - that way, you can use the RunWorkerCompleted Event to detect the end of processing automatically. That's the one I would go with!
   
Comments
Sergey Alexandrovich Kryukov 29-Oct-12 11:27am
   
Polling is also not a notification, this is a pulling design. The problem is not so simple.
Event use is right thing, of course, but I believe it needs more explanation...
Please see my answer where I explain a productive approach.
--SA
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 2

You could simply add another loop and do a Join on each thread. After the loop is completed, all threads are as well.
foreach (Thread t in th)
{
   t.Join();
}


Good luck!
   
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 4

I assume you want to do it asynchronously. (Synchronously, you would call Thread.Join, and that would be a blocking call for a calling thread. Not always, but in many cases it could defeat the purpose of threading, because the threads involved are not really executed in parallel during this blocking. :-))

So, the thread which is about to be complete should actively notify about it. This should be some code in this thread itself. First of all, if this is a console application; and if you only need to print "Done". In this case, the solution is as simply as printing it in this very thread.

I don't to use your confusion to go away with such a simple but not very useful solution though. :-) In a more general case, you would need to do something in a loosely-coupled piece of code. In this case, you would need to get some notification. You only should understand that the notification will come in a separate thread (the one about to be complete) anyway. You will need to do something about it.

To provide a notification, I recommend to create a thread wrapper, define an event in the wrapper class, and add an event handler by any class using the wrapper.
class ThreadWrapper {

    internal ThreadWrapper(/*..*/) {
        /* pass whatever needed from out side */
        Thread = new System.Threading.Thread(Body); //don't tell my it is illegal!
    } //ThreadWrapper

    internal event System.EventHandler Complete;  

    internal void Start() { this.Thread.Start(); }
    internal void Abort() { this.Thread.Abort(); }
 
    //and so on...

    void Body() {
        if (this.SomeByRefParameter == null) //can read
            this.SomeByRefParameter = new System.Text.StringBuilder(); //can modify
        //why? because this member is non-static, "this" parameter is used
        //...
        if (Complete != null)
            Complete.Invoke(this, new System.EventHandler()); // this will call a handler (handlers) to notify
    } //Body

    System.Threading.Thread Thread;   

}


Please see my past answer on the techniques based on thread wrappers:
How to pass ref parameter to the thread[^],
change paramters of thread (producer) after it started[^].

Not, when you add an event handler, it will be called in the thread wrapped in the ThreadWrapper. But the handler was created in some other thread, it may use some members of other class created in another thread, which is not always possible. For example, if this other thread is a UI thread, you won't be able to use any UI members directly.

The very general mechanism is to delegate some method to be called in another thread (other then the thread calling an event handle). In general case, I described such mechanism in my article, complete with source code and usage samples:
Simple Blocking Queue for Thread Communication and Inter-thread Invocation[^].

This method would allow to cross-invoke a call to another thread, which should be programmed in a certain way though. Everything is explained in my article, with samples.

With UI, such mechanism is already exists. Keep reading.

You cannot call anything related to UI from non-UI thread. Instead, you need to use the method Invoke or BeginInvoke of System.Windows.Threading.Dispatcher (for both Forms or WPF) or System.Windows.Forms.Control (Forms only).

You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^].

See also more references on threading:
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

—SA
   
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 5

Hello,
Here is other solution. As .NET threads cannot be used in wait functions:
static void Main(string[] args)
{
    int ThreadCount =Convert.ToInt32(ConfigurationManager.AppSettings["Threads"]);
    List<Thread> th = new List<Thread>();
    List<WaitHandle> handles = new List<WaitHandle>(); // Create Events list
    for (int i = 0; i < ThreadCount; i++)
    {
       Thread t = new Thread(print);
       handles.Add(new ManualResetEvent(false)); // Manual reset event for each thread with non signaled state
       th.Add(t);
    }
    for (int i = 0; i < th.Count; i++)
    {
        th[i].Start(handles[i]); // start paramettrized threads with each event as argument
    }
    WaitHandle.WaitAll(handles.ToArray()); // wait all threads to complete
}

static public void print(object _object)
{
    try // we should use try so the signal is performed in any case
    {
        // Your code - probably unsafe 
        Console.WriteLine("123");
    }
    finally 
    {
        // finally will executed even if exception take place or user abort the thread
        // so we always have this code to be executed
        if (_object != null && _object.GetType().IsSubclassOf(typeof(EventWaitHandle))) 
        {
            // once we have argument and it any event - we signal it
            (_object as EventWaitHandle).Set();
        }
    }
}

Difference from Join - is that Join wait for one thread, simple modify of wait line we can define once thread finished:
// check for each thread
while (handles.Count > 0)
{
    int nIndex = WaitHandle.WaitAny(handles.ToArray());
    handles.RemoveAt(nIndex); // we remove handle from wait list
    Console.WriteLine("DONE"); // print that thread is done
}

In code above you can check once each thread is finished with little modify. Also if you want async notify you can make it as described in solution 4. Or as alternate you can pass event delegate as argument for a thread.
static void ThreadFinished()
{
    Console.WriteLine("DONE"); // print that thread is done
}

private delegate void ThreadFinishProc();

static void Main(string[] args)
{
    int ThreadCount =Convert.ToInt32(ConfigurationManager.AppSettings["Threads"]);
    List<Thread> th = new List<Thread>();
    for (int i = 0; i < ThreadCount; i++)
    {
       Thread t = new Thread(print);
       th.Add(t);
    }
    // our delegate
    ThreadFinishProc _proc = new ThreadFinishProc(ThreadFinished);
    for (int i = 0; i < th.Count; i++)
    {
        th[i].Start(_proc); // start paramettrized threads with delegate
    }
    // the code continue without waiting
}

static public void print(object _object)
{
    try // we should use try so the signal is performed in any case
    {
        // Your code - probably unsafe 
        Console.WriteLine("123");
    }
    finally
    {
        // Now we check for the delegate
        if (_object != null && _object.GetType() == typeof(ThreadFinishProc))
        {
            // invoke our delegate
            (_object as ThreadFinishProc)();
        }
    }
}

Regards,
Maxim.
   
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 1

Use global object to check the thread completion.
Try the following code.

public class Sample
{
public int ThreadCount;
static void Main(string[] args)
{
    ThreadCount =Convert.ToInt32ConfigurationManager.AppSettings["Threads"]);
    List<Thread> th = new List<Thread>();
    for (int i = 0; i < ThreadCount; i++)
    {
       Thread t = new Thread(print);
       th.Add(t);
    }
    foreach (Thread t in th)
    {
        t.Start();
    }

while(ThreadCount!=0)
{}
//Print your stmt here.
}
public void print()
{
    console.writeline("123");
    ThreadCount --; 
}
}
   
v3
Comments
OriginalGriff 29-Oct-12 11:21am
   
Not sure that is a good idea - is the postdecrement operator thread safe? I can't see anything in MSDN which says it is...
Admittedly, I can't see anything which says it isn't, but using a lock with this would be a much, much better idea.
Street Racers 29-Oct-12 11:33am
   
I do agree, it's not a good practice, but it's a very simple solution without any complex or expensive operation. Even I had doubt why two loops: one 'for' loop and one 'foreach' loop(Two times looping and wasting memory is also not good practice & expensive).
OriginalGriff 29-Oct-12 11:49am
   
It is possible that the OP wants to get the threads started at as-close-as-possible the same moment. Since creating a new Thread object takes an unpredictable amount of time (Garbage collection for example could kick in at any time while allocating a number of new items) doing it in two separate loops is a way to minimize the effects of this.

Or more likely he didn't think when he wrote the code. :sigh:

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


Advertise | Privacy | Cookies | Terms of Service
Web04 | 2.8.190306.1 | Last Updated 30 Oct 2012
Copyright © CodeProject, 1999-2019
All Rights Reserved.
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100