Wednesday, January 7, 2009

WaitHandle.WaitAll Limitation

WaitHanlde.WaitAll function has limitation about no. of WaitHandles it can handle. As it take array of WaitHandles so one can think it can handle any no. of WaitHandles, but it is not true. It can only handle 64 waithandles. When array exceed this value it display following error.

“The number of WaitHandles must be less than or equal to 64.”

Example that cause this error.

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

namespace WaitHandle_Limitation
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                List<ManualResetEvent> events = new List<ManualResetEvent>();
                for (int i = 0; i < 100; i++)
                {
                    Thread th = new Thread(new ParameterizedThreadStart(ThreadRunner));
                    ThreadParamObj obj = new ThreadParamObj();
                    obj.startval = (i*100);
                    obj.endval = (i*100)+10;
                    obj.eve = new ManualResetEvent(false);
                    events.Add(obj.eve);
                    th.Start(obj);
                }
                WaitHandle.WaitAll(events.ToArray());
/* Cause error when event.ToArray return array larger than 64. Here to cause error i used 100. So it will create array of 100. */
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + ex.StackTrace);           
            }
            Console.ReadLine();           
        }

        static void ThreadRunner(object thObj)
        {
            ThreadParamObj obj = (ThreadParamObj)thObj;
            if (obj != null && obj.startval < obj.endval)
            {
                for (int i = obj.startval; i < obj.endval; i++)
                {
                    Console.WriteLine("Thread ID {0} Value : {1}", Thread.CurrentThread.ManagedThreadId, i.ToString());
                }
                obj.eve.Set();
            }

        }
    }

    class ThreadParamObj
    {
        public int startval;
        public int endval;
        public ManualResetEvent eve;
    }
}


To overcome this error one solution is make chunk of 64 thread first then wait for that all thread complete then start another 64 chunk.

// Possible Solution by use of 64 Chunks.

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

namespace WaitHandle_Limitation
{
    class Program
    {
        static void Main(string[] args)
        {
            int noofthread = 100;
            int startindex = 0;
            int endindex = 64;
            try
            {
                int noofchunk = (int)Math.Ceiling(((double)noofthread / 64.00));
                if (noofthread < endindex)
                    endindex = noofthread;
                for (int chunk = 0; chunk < noofchunk; chunk++)
                {
                    List<ManualResetEvent> events = new List<ManualResetEvent>();
                    for (int i = startindex; i < endindex; i++)
                    {
                        Thread th = new Thread(new ParameterizedThreadStart(ThreadRunner));
                        ThreadParamObj obj = new ThreadParamObj();
                        obj.startval = (i * 100);
                        obj.endval = (i * 100) + 10;
                        obj.eve = new ManualResetEvent(false);
                        events.Add(obj.eve);
                        th.Start(obj);
                    }
                    WaitHandle.WaitAll(events.ToArray());
                    startindex += 64;
                    endindex += 64;
                    if (endindex > noofthread)
                    {
                        endindex = noofthread;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + ex.StackTrace);           
            }
            Console.WriteLine("Completed");
            Console.ReadLine();           
        }

        static void ThreadRunner(object thObj)
        {
            ThreadParamObj obj = (ThreadParamObj)thObj;
            if (obj != null && obj.startval < obj.endval)
            {
                for (int i = obj.startval; i < obj.endval; i++)
                {
                    Console.WriteLine("Thread ID {0} Value : {1}", Thread.CurrentThread.ManagedThreadId, i.ToString());
                }
                obj.eve.Set();
            }

        }
    }
    class ThreadParamObj
    {
        public int startval;
        public int endval;
        public ManualResetEvent eve;
    }
}


Let me know if you have any other ideas or comment on this.

Another possible solution at http://dotnetstep.blogspot.com/2009/01/threadpool-wait-for-all-thread-to.html.

2 comments:

varun said...

I had same problem but can't we instead of chunks use a queue when any one thread is processed we add one more thread so we use fully utilize computing power.

dotnetstep said...

Hello,

Can you please provide some more detail of your idea ?

Actually i provided chuncks solutions in same article.

Waiting for your reply...

Thanks.