Introduction
WaitHandles must be less than or equal to 64? This exception is thrown when a developer wants to do
WaitAll()
or WaitAny()
for the field resetEvents
(which is
WaitHandled[] resetEvents
)
where the capacity is greater than 64. If you look at the source code of the
WaitHandled
class in the .NET Framework you will see that there is
a condition if("some field"<64)
. I built ThreadWaitHandle.cs which includes static methods
WaitAll()
and WaitAny()
for solving this problem manually.
Using the code
This class includes two static methods WaitAll()
and WaitAny()
. Like
WaitHandle
developer sends an array to this method and gets a result. For solving limitation problems I use recursion
and reset events for invoking all subarrays at the same time. Simply copy ThreadWaitHandler.cs and paste
it in your project for use.
public class ThreadWaitHandler
{
private const int Limit = 64;
public static void WaitAll(WaitHandle[] waitHandles)
{
WaitAllHandled(waitHandles);
}
public static void WaitAllHandled(WaitHandle[] waitHandles)
{
if (waitHandles.Length <= Limit)
{
WaitHandle.WaitAll(waitHandles);
return;
}
ManualResetEvent resetEvent = new ManualResetEvent(false);
for (int i = 0; i < waitHandles.Length / Limit + 1; i++)
{
int localI = i;
new Thread(() =>
{
WaitAllHandled(waitHandles.Skip(localI * Limit).Take(
GetNumberOfTakedElements(localI, waitHandles)).ToArray());
resetEvent.Set();
}).Start();
}
resetEvent.WaitOne();
}
public static int WaitAny(WaitHandle[] waitHandles)
{
return waitAnyHandled(waitHandles, 0);
}
private static int waitAnyHandled(WaitHandle[] waitHandles, int offset)
{
if (waitHandles.Length <= Limit)
{
int result = WaitHandle.WaitAny(waitHandles) + offset * Limit;
return result;
}
ManualResetEvent[] resetEvents =
new ManualResetEvent[(int)Math.Ceiling(waitHandles.Length / (double)Limit)];
DataRecursion[] dataRecursions = new DataRecursion[resetEvents.Length];
for (int i = 0; i < resetEvents.Length; i++)
{
ManualResetEvent resetEvent = new ManualResetEvent(false);
resetEvents[i] = resetEvent;
int localI = i;
new Thread(() =>
{
int originalIndex = waitAnyHandled(waitHandles.Skip(localI * Limit).Take(
GetNumberOfTakedElements(localI, waitHandles)).ToArray(), localI);
dataRecursions[localI] = new DataRecursion(originalIndex, localI);
resetEvent.Set();
}).Start();
}
int index = WaitHandle.WaitAny(resetEvents);
return GetWaitAnyResultByIndex(index, dataRecursions);
}
private static int GetWaitAnyResultByIndex(int index, DataRecursion[] dataRecursions)
{
for (int i = 0; i < dataRecursions.Length; i++)
{
if (i == index)
{
return dataRecursions[i].Originalindex;
}
}
return -1;
}
private static int GetNumberOfTakedElements(int skip, WaitHandle[] waitHandles)
{
if (((int)Math.Ceiling(waitHandles.Length / (double)Limit) - skip) == 1)
{
return waitHandles.Length - skip * Limit;
}
return Limit;
}
}
public class DataRecursion
{
public int Originalindex { get; set; }
public int EventIndex { get; set; }
public DataRecursion(int orginalIndex, int eventIndex)
{
Originalindex = orginalIndex;
EventIndex = eventIndex;
}
}
Points of Interest
I think this way we will get an optimal solution for this problem. I
have read other solutions but for WaitAny()
the solutions were
unacceptable.
If you want to use 500 or more threads, you must pay attention to speed of compilation. As when you compile
the application the first thread will be set first until others are reading.
History
I will submit all updates and changes here. If you have another solution,
please write and discuss.