views:

142

answers:

6

I create my threads as

 for (int i = 0; i < threadCount; i++)
 {
     Searcher src = new Searcher(i, this);

     threads[i] = new Thread(new ThreadStart(src.getIpRange));
     threads[i].Name = string.Format(i.ToString());
  }

  foreach (Thread t in threads)
  {
     t.Start();
  }

with threadCount(= 100, 150, 255 etc...) but I can't learn how many threads working. on execute time.

and I want to control when all threads finishes their job. and give me a message like "All threads are dead, jobs completed..." like backgroundWorker's RunWorkerCompleted event

A: 

Why can't you use critical section protected single variable to control a number of active threads? Thread function can modify this variable (having entered critical section, of course).

FractalizeR
can you expain what is the "critical section protected single variable " ? and how can I use
Rapunzo
Here are some examples and definition: http://en.wikipedia.org/wiki/Critical_section
FractalizeR
+1  A: 

Determining when all the threads are finished is simple.

for (int i = 0; i < threadCount; i++)
{
    threads[i].Join();
}

Console.WriteLine("All threads are done!");

Can you elaborate on your other requirements?

Winston Smith
I tryed this but blocking the progress.
Rapunzo
@Rapunzo - indeed, that's the point. `Thread.Join` is a blocking call - hence `Console.WriteLine` won't execute until all threads are finished. You can run this piece of code on another thread, with appropriate synchronisation on whichever notification mechanism you choose. I used `Console.WriteLine` here for simplicity.
Winston Smith
+1  A: 

You can check the ThreadState property of the Thread.

Might be better to use async methods. This gives you a WaitHandle object, and you can use WaitHandle.WaitAll to wait for all of your async methods to finish.

Here's an intro to asynchronous programming: http://msdn.microsoft.com/en-us/library/aa719598%28v=VS.71%29.aspx

Jerome
Can you explain async method?
Rapunzo
You call your method using BeginInvoke() instead of calling it directly
Jerome
+1  A: 

First, I have to point out that creating 100, 150, 255, etc. threads is probably not a good idea. You might be better off using the ThreadPool or Task class (if using .NET 4.0). Aside from that there are two well established methods for waiting until all threads complete.

Join the thread.

Thread.Join blocks until the target thread finishes.

for (int i = 0; i < threadCount; i++) 
{ 
   Searcher src = new Searcher(i, this); 
   threads[i] = new Thread(new ThreadStart(src.getIpRange)); 
   threads[i].Name = string.Format(i.ToString()); 
} 

foreach (Thread t in threads) 
{ 
   t.Start(); 
} 

foreach (Thread t in threads)
{
   t.Join(); 
}

Use a CountdownEvent.

A CountdownEvent waits until its internal count reaches zero. This method is better suited if you want to use the ThreadPool. If you are not using .NET 4.0 you can get a really simple implementation over at Joe Albahari's website.

var finished = new CountdownEvent(1);

for (int i = 0; i < threadCount; i++) 
{ 
   finished.AddCount();
   Searcher src = new Searcher(i, this); 
   threads[i] = new Thread(
     () =>
     {
        try
        {
          src.getIpRange();
        }
        finally
        {
          finished.Signal();
        }
     }
   threads[i].Name = string.Format(i.ToString()); 
} 

foreach (Thread t in threads) 
{ 
   t.Start(); 
} 

finished.Signal();
finished.WaitOne();
Brian Gideon
is countdownevent defined in .net 3.5?
Rapunzo
No, I updated my answer to include a link with a simple implementation.
Brian Gideon
+1  A: 

You definitely want to use the Task class for this or a higher-level concept like Parallel.ForEach. Using the Thread class directly is quite painful.

I recently wrote a blog post comparing various asynchronous approaches, listed in order from best (Task) to worst (Thread).

Here's an example using Task, demonstrating what you wanted to do:

// Start all tasks
var threads = new Task[threadCount];
for (int i = 0; i < threadCount; i++) 
{ 
  Searcher src = new Searcher(i, this); 
  threads[i] = Task.Factory.StartNew(src.getIpRange);
}

// How many are running right now?
var runningCount = threads.Count(x => x.Status == TaskStatus.Running);

// Register a callback when they have all completed (this does not block)
Task.Factory.ContinueWhenAll(threads, MyCallback);
Stephen Cleary
I try to add using System.Threading.Tasks; to my project but get an error: The type or namespace name 'Tasks' does not exist in the namespace 'System.Threading' (are you missing an assembly reference?)
Rapunzo
To use the `Task` class, you'll need either .NET 4.0 or the [Rx library](http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx) for .NET 3.5.
Stephen Cleary
+1  A: 

Add a delegate to Searcher and pass it a callback method from your main thread that each thread will call when it finishes. As you launch each thread, add it to a Dictionary keyed by the thread's ManagedThreadId. When each thread finishes, the callback removes the thread from the Dictionary and checks to see if the count is zero.

        Dictionary<int, Thread> activeThreads = new Dictionary<int, Thread>();            

           for (int i = 0; i < threadCount; i++)
            {
                Searcher src = new Searcher(i, this);
                src.Done = new SearcherDoneDelegate(ThreadDone);
                threads[i] = new Thread(new ThreadStart(src.getIpRange));
                threads[i].Name = string.Format(i.ToString());
            }

            foreach (Thread t in threads)
            {
                lock (activeThreads)
                {
                    activeThreads.Add(t.ManagedThreadId, t);
                }
                t.Start();
            }


        }
        public void ThreadDone(int threadIdArg)
        {
            lock (activeThreads)
            {
                activeThreads.Remove(threadIdArg);
                if (activeThreads.Count == 0)
                {
                    // all done
                }
            }
        }

        public delegate void SearcherDoneDelegate(int threadIdArg);
        public static object locker = new object();



        public class Searcher
        {
            public SearcherDoneDelegate Done { get; set; }
            public void getIpRange()
            {
                Done(Thread.CurrentThread.ManagedThreadId);
            }
        }

If you have more threads than you want to run at one time, put them into a Queue and peel them off as older threads finish (use the callback).

ebpower
thanks for solution but (activeThreads.Count == 0) doesnt work healty, many times it fails! here is my codeif ((activeThreads.Count) == 0) { j++; progressBar1.Value = 0; btnSearch.Enabled = true; }in this case progressbar1. value getting 0 and many times growing up after gettin 0 again. and I cant be sure from threads are done
Rapunzo
@Rapunzo - what's happening is that you're starting each thread as soon as it's created, and the initial threads are finishing before the latter threads have started. The quick way to get around this is to move the t.Start() to a second loop so you create all of them before starting any of them. A more elegant approach is to put the created threads in a Queue<Thread> and read them using a producer-consumer pattern. This also lets you control the number of concurrent threads.
ebpower