1
Answer

Main thread ends before worker threads do--help please??

Photo of Eric Blair

Eric Blair

17y
2.4k
1
Hello,

I've written a simple app as a test to run mutliple threads from a pool. I'm able to do this, but what's happening is that the main thread finishes before all the workers do.  So the Console shows:
"Main thread exits." in between the worker thread strings.

Can anyone see what I'm doing wrong please?

Thanks in Advance!

Here's my code:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Reflection;

namespace ThreadPool2
{
   public static class Example
   {     
      private static int _MaxThreads=2;
      private static ManualResetEvent _DoneEvent;
     
      public static void Main()
      {
         // One event is used for each Method object
         ManualResetEvent[] aDoneEvents = new ManualResetEvent[3];

         Type aTestClass = typeof(Tests);
                
         ThreadPool.SetMaxThreads(_MaxThreads, _MaxThreads);

         MethodInfo[] aMethods = aTestClass.GetMethods();
         int i = 0;
         foreach(MethodInfo aMethod in aMethods)
            if(aMethod.ReturnType.Name == "Void")
            {              
               aDoneEvents[i] = new ManualResetEvent(false);
               _DoneEvent = aDoneEvents[i];
               ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), aMethod);

               i++;              
            }
        
         WaitHandle.WaitAll(aDoneEvents); //code gets stuck here but I can't see why!

         Console.WriteLine("Main thread exits.");
         Console.Read();
      }//Main

      // This thread procedure performs the task.
      static void ThreadProc(Object stateInfo)
      {
         object[] aObj = null;

         Tests aTests = new Tests(_DoneEvent);

         MethodInfo aMethod = stateInfo as MethodInfo;

         aMethod.Invoke(aTests, aObj);
                 
         aTests.DoneEvent.Set();
                 
      }//ThreadProc
   }
}



using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ThreadPool2
{
   public class Tests
   {
      public ManualResetEvent DoneEvent;

      public Tests(ManualResetEvent theDoneEvent)
      {
         DoneEvent = theDoneEvent;
      }


      public void Test1()
      {
         Console.WriteLine("This is Test 1 Start...");
         Thread.Sleep(2000);
         Console.WriteLine("This is Test 1 Stop...");
       
      }

      public void Test2()
      {

         Console.WriteLine("This is Test 2 Start...");
         Thread.Sleep(2000);
         Console.WriteLine("This is Test 2 Stop...");

       }

      public void Test3()
      {

         Console.WriteLine("This is Test 3 Start...");
         Thread.Sleep(2000);
         Console.WriteLine("This is Test 3 Stop...");

      }

   }
}




Answers (1)

0
Photo of Eric Blair
NA 3 0 17y
I should have realized how sensitive threads are to timing.
Instead of having aglobal DoneEvents, I need to pass it within this loop immediately because by the time I access it beyond here, it wouls have gotten out of synch. So I bundled that data for my callback into a lightweight class that takes the doevents and the method from within the loop and passes it to my worker method.     

The gist of the fix is as follows.

class bundleddata
{
       MethodInfo Method;
      
ManualResetEvent MRE;
}

...


 MethodInfo[] aMethods = aTestClass.GetMethods();
         int i = 0;
         foreach(MethodInfo aMethod in aMethods)
            if(aMethod.ReturnType.Name == "Void")
            {         
               
bundleddata aBD=new bundleddata();
               aDoneEvents[i] = new ManualResetEvent(false);
                aBD.Method=
aMethod ;
               aBD.MRE = aDoneEvents[i];
               ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), aBD);

               i++;              
            }