Threadpool Issue with WaitHandle.WaitAll FatalExecutionEngineError  
Author Message
Vincent Fournier





PostPosted: .NET Base Class Library, Threadpool Issue with WaitHandle.WaitAll FatalExecutionEngineError Top

I have a process that goes out to each machine on the network and executes a few WMI calls. In the case that there is an error it takes about 5 seconds before it continues forward. 5 Seconds X 3000 Computers is more time that I have available. So, I have been messing around with ThreadPools. My thought is that I will kick off the WMI calls for 10 different machines then wait for them all to return. This way it only takes 5 seconds for each group of 10 machines.

I have been using the Fibonacci Example to come up with the test code below but on my WaitHandle.WaitAll I am getting a FatalExecutionEngineError:

Error: FatalExecutionEngineError was detected

Message: The runtime has encountered a fatal error. The address of the error was at 0x7a07adc5, on thread 0x1320. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

Does anyone see anything obvious that I am doing wrong in the code below

public class ThreadPoolExample

{

static void Main()

{

int intConcurrentThreads = 10; int intThreadGroup = 0; int intCurrentThread = 0;

ManualResetEvent[] doneEvents = new ManualResetEvent[intConcurrentThreads + 1];

Console.WriteLine("Main Start!");

Console.WriteLine(" Group: " + intThreadGroup.ToString() + " Started.");

for (int i = 0; i < 35; i++)

{

if (Math.IEEERemainder((double)(i), intConcurrentThreads) == 0 && i > 0)

{

WaitHandle.WaitAll(doneEvents);

Console.WriteLine(" Group: " + intThreadGroup.ToString() + " Stopped.");

intThreadGroup = intThreadGroup + 1; intCurrentThread = 0;

Console.WriteLine(" Group: " + intThreadGroup.ToString() + " Started.");

}

doneEvents[intCurrentThread] = new ManualResetEvent(false);

UpdateComputerThread updateComputerThread = new UpdateComputerThread(i, new DataView(), doneEvents[intCurrentThread]);

ThreadPool.QueueUserWorkItem(updateComputerThread.ThreadPoolCallback, intCurrentThread);

intCurrentThread = intCurrentThread + 1;

}

WaitHandle.WaitAll(doneEvents);

Console.WriteLine("Main Done!");

}

}

public class UpdateComputerThread

{

public UpdateComputerThread(int row, DataView dv, ManualResetEvent doneEvent)

{

_row = row;

_dv = dv;

_doneEvent = doneEvent;

}

// Wrapper method for use with thread pool.

public void ThreadPoolCallback(Object threadContext)

{

int threadIndex = (int)threadContext;

Console.WriteLine(" thread {0} started...", threadIndex);

Thread.Sleep(6000); //Simulate Making the WMI Call to the Computer

Console.WriteLine(" thread {0} Done...", threadIndex);

_doneEvent.Set();

}

public int Row { get { return _row; } }

private int _row;

public DataView Dv { get { return _dv; } }

private DataView _dv;

ManualResetEvent _doneEvent;

}




.NET Development18  
 
 
Mark Dawson





PostPosted: .NET Base Class Library, Threadpool Issue with WaitHandle.WaitAll FatalExecutionEngineError Top

Hi Vincent,

I just compiled and ran your code and it worked for me (I had to modify the WaitHandle array definition to not be +1 at the beginning of the code), with a value of 10 threads in the group. Are you seeing this error using a value of 10 It is probably not a good idea to use thread pool threads like you are, since these threads should only be used for very quick operations and the pool is also used by the CLR for its own internal workings, each process gets a pool of 25 threads. I would recommend you create several of your own threads rather that using the threadpool if you are going to be using a lot of threads and they are waiting for a period of time.

Mark.



 
 
Peter Ritchie





PostPosted: .NET Base Class Library, Threadpool Issue with WaitHandle.WaitAll FatalExecutionEngineError Top

Make sure you Main method is attributed with MTAThread. WaitAll is not supported in STAThread threads.

 
 
Vincent Fournier





PostPosted: .NET Base Class Library, Threadpool Issue with WaitHandle.WaitAll FatalExecutionEngineError Top

Could you explain this a little further

 
 
Vincent Fournier





PostPosted: .NET Base Class Library, Threadpool Issue with WaitHandle.WaitAll FatalExecutionEngineError Top

This is my first try at working with threads. Would you happen to have an example of how to not use threadpools

 
 
Mark Dawson





PostPosted: .NET Base Class Library, Threadpool Issue with WaitHandle.WaitAll FatalExecutionEngineError Top

Hi,

  this looks like a perfect scenario for a producer / consumer type of solution.  Where there are threads putting data into a queue and other threads processing those items as they become available.  So you can queue a number of WMI requests and then worker threads will pick those off while there are items still left in the queue.  Below is an example of how you can do this,  the code will create a number of threads, each thread will wait using Monitor.Wait until it is signaled by the consumer thread which uses Monitor.Pulse to wake up a thread.  The key is that if a Monitor.Pulse call takes place and no thread is waiting on the lock then the pulse will appear not to have happened, so threads keep processing while there are items in the queue, only waiting while the queue is empty.  Hope this makes sense:

 

using System;

using System.Collections.Generic;

using System.Threading;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            ProducerConsumer pc = new ProducerConsumer(5);

           

            //Create a stream of data to be processed

            for (int i = 0; i < 100; ++i)

            {

                pc.Produce(i.ToString());

            }

 

            //Indicate all items are queued so threads will exit

            //when queue is empty

            pc.AllItemsAdded();

 

            //Wait a while for data to be processed.

            //Ideally have a syncronization method to know when all worker items are complete

            Thread.Sleep(60000);

        }

    }

 

    class ProducerConsumer

    {

        private Random random = new Random();

        private bool noMoreWork = false;

        private readonly object workItemLock = new object();

        private Queue<string> workItems = new Queue<string>();

 

        public ProducerConsumer(int numberOfWorkerThreads)

        { 

            //Create the required number of worker threads

            for (int i = 0; i < numberOfWorkerThreads; ++i)

            {

                new Thread(new ThreadStart(Consume)).Start();

            }

        }

 

        //Add a new work item to the queue

        public void Produce(string wmiRequest)

        {

            lock (this.workItemLock)

            {

                //Add new work item to the list

                workItems.Enqueue(wmiRequest);

 

                //Notify a thread that data has arrived

                Monitor.Pulse(this.workItemLock);

            }

        }

 

        private void Consume()

        {

            string wmiRequest;

 

            while (true)

            {

                lock(this.workItemLock)

                {

                    //Check to see if there is any work to do

                    while(this.workItems.Count == 0)

                    {

                        //If user has indicated there will be

                        //no more work then let the thread exit

                        if (this.noMoreWork)

                        {

                            return;

                        }

 

                        //Wait for work

                        Monitor.Wait(this.workItemLock);

                    }

 

                    //Take an item of the queue

                    wmiRequest = this.workItems.Dequeue();

                }

 

                //Do the work outside of the lock so that items can be

                //added to the queue and removed by other threads

 

                //Simulate work time

                Thread.Sleep(this.random.Next(3001));

 

                Console.WriteLine(wmiRequest);

            }

        }

 

        //Indicates that there will be no more work, once the

        //queue is empty the worker threads can exit

        public void AllItemsAdded()

        {

            lock (this.workItemLock)

            {

                this.noMoreWork = true;

 

                //Wake everyone up if they are waiting for data

                Monitor.PulseAll(this.workItemLock);

            }

        }

    }

}

 

Mark.