3

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

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Rapunzo
  • 966
  • 5
  • 21
  • 42
  • It's hard for me to imagine an app where 255 identical threads would be optimal. Remember that the max number of threads that can run systemwide at any given time = the number of independent CPU cores in your target hardware. fwiw it is my experience (Win XP SP2) that thread creation fails after about 120 in a single process. This was in a test app implemented with one thread per socket-based app client. No way I would implement the actual production code that way. – Steve Townsend Aug 30 '10 at 17:18
  • I am working on a network applicationi so my threads are spending much time. and I thing this is not a overload for cpu – Rapunzo Sep 03 '10 at 15:05

6 Answers6

1

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
  • 21,585
  • 10
  • 60
  • 75
  • I tryed this but blocking the progress. – Rapunzo Aug 27 '10 at 12:32
  • @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 Aug 27 '10 at 14:10
1

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
  • 1,162
  • 1
  • 6
  • 12
1

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
  • 47,849
  • 13
  • 107
  • 150
1

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
  • 437,863
  • 77
  • 675
  • 810
  • 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 Aug 27 '10 at 14:05
  • 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 Aug 27 '10 at 15:10
1

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).

Ed Power
  • 8,310
  • 3
  • 36
  • 42
  • thanks for solution but (activeThreads.Count == 0) doesnt work healty, many times it fails! here is my code if ((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 Sep 03 '10 at 15:02
  • @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 and read them using a producer-consumer pattern. This also lets you control the number of concurrent threads. – Ed Power Sep 03 '10 at 17:35
0

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).

Vladislav Rastrusny
  • 29,378
  • 23
  • 95
  • 156