Workaround for the WaitHandle.WaitAll 64 handle limit?
Create a variable that keeps track of the number of running tasks:
int numberOfTasks = 100;
Create a signal:
ManualResetEvent signal = new ManualResetEvent(false);
Decrement the number of tasks whenever a task is finished:
if (Interlocked.Decrement(ref numberOftasks) == 0)
{
If there is no task remaining, set the signal:
signal.Set();
}
Meanwhile, somewhere else, wait for the signal to be set:
signal.WaitOne();
Workaround for the WaitHandle.WaitAll 64 handle limit?
Create a variable that keeps track of the number of running tasks:
int numberOfTasks = 100;
Create a signal:
ManualResetEvent signal = new ManualResetEvent(false);
Decrement the number of tasks whenever a task is finished:
if (Interlocked.Decrement(ref numberOftasks) == 0)
{
If there is no task remaining, set the signal:
signal.Set();
}
Meanwhile, somewhere else, wait for the signal to be set:
signal.WaitOne();
Handle more than 64 thread at the same time
The winapi restriction on the number of handles you can wait on at the same time is a pretty hard one. It is just not necessary, you'll get the exact same outcome if you wait for each individual one:
' Wait for all threads in pool to calculate.
For i As Integer = 0 To FibonacciCalculations
doneEvents(i).WaitOne()
Next
And note how you can now combine this with the next loop, making your program more efficient since you overlap the calculation with the display. So you really want to favor this instead:
' Display the results.
For i As Integer = 0 To FibonacciCalculations
doneEvents(i).WaitOne()
Dim f As Fibonacci = fibArray(i)
Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN)
Next
How to implement waitAny on more than 64 handles?
You might want to consider implementing something like a queue for notification packets for the 'waitAny' thread to wait on. When one of your multitude of threads completes it's operation, it places a notification packet on the queue. Your waitAny
turns into a wait on a single event that indicates something is in the queue.
C# Threads, WaitHandle.WaitAll
I would not use WaitHandle.WaitAll
. There are a couple of problems with this approach.
- There is a 64 handle limit.
- It cannot be used on an STA thread.
- It promotes patterns that depend on the creation of multiple
WaitHandle
instances which obviously consume resource.
Instead, I typically use the CountdownEvent
class when I want to wait on multiple events. Now, the problem you will have with that is that it still requires you to call Wait
on some thread which is exactly what you are trying to avoid. The standard mechanism to avoid making a blocking call is to use the ThreadPool.RegisterWaitForSingleObject
method. But, unfortunately that takes a WaitHandle
and CountdownEvent
does not inherit from that class.
The solution is to create your own CountdownWaitHandle
class that can be used in the ThreadPool.RegisterWaitForSingleObject
method. This approach will allow you to specify a callback delegate that will be executed once the WaitHandle
is signaled.
Here is the most basic implemenation for the CountdownWaitHandle
class. You will have to add all of the necessary harding code yourself, but this will get you started.
public class CountdownWaitHandle : WaitHandle
{
private int m_Count = 0;
private ManualResetEvent m_Event = new ManualResetEvent(false);
public CountdownWaitHandle(int initialCount)
{
m_Count = initialCount;
}
public void AddCount()
{
Interlocked.Increment(ref m_Count);
}
public void Signal()
{
if (Interlocked.Decrement(ref m_Count) == 0)
{
m_Event.Set();
}
}
public override bool WaitOne()
{
return m_Event.WaitOne();
}
}
The idea here is that instead of using many different WaitHandle
instances you use a single CountdownWaitHandle
instance. Initialize the instance with the desired count and then call Signal
to decrement the count. Once the count gets to zero the WaitHandle
will go into the signaled state. So instead of calling Set
on multiple WaitHandle
instances and blocking with WaitHandle.WaitAll
you now call Signal
on this one instance and block by calling WaitOne
. And again, you can push off the blocking call to the thread pool by using TheadPool.RegisterWaitForSingleObject
which will invoke a callback when the WaitHandle
is signaled.
Threading Exception: The number of WaitHandles must be less than or equal to 64
You don't need an array of 128 manual events to check for completion of all 128 threads.
Create only one manual reset event and a plain integer starting at 128. Decrement that integer using Interlocked.Decrement
at the end of ProcessSingleCategoryProduct
, and only signal the event when the count reaches zero:
if (Interlocked.Decrement(ByRef myCounter) = 0) myEvent.Set();
Then declare only one Threading.ManualResetEvent
as opposed to an array of them, and you can call WaitOne
instead of WaitAll
on it, and you are done.
See also usr's comment for an easier alternative in case you have .NET 4.
Threadpool WaitAll 64 [Leadtools]
You waiting for those events does not cause the tasks to fail. More likely there is an exception which you do not notice (uncaught or swallowed).
Make your processing Task
based and use Task.WaitAll
. No limits there. You'll also get automatic error propagation.
Related Topics
Linq Query Built in Foreach Loop Always Takes Parameter Value from Last Iteration
Ef4 Code First: How to Add a Relationship Without Adding a Navigation Property
Stop SQL Query Execution from .Net Code
Curiously Recurring Template Pattern and Generics Constraints (C#)
Windows Forms Graphic Issue on Windows 10 Os
Func Delegate with Ref Variable
Does Foreach Evaluate the Array at Every Iteration
Get Values from Process Standardoutput
Compile-Time and Runtime Casting C#
C# Regular Expressions, String Between Single Quotes
Hook on Default "Paste" Event of Winforms Textbox Control
How to Get the Access Token from a Blazor (Server-Side) Web App
Itextsharp: Adjust 2 Elements on Exactly One Page
An Error Occurred During Report Processing. -Rldc Reporting in ASP.NET MVC
If Strings Are Immutable in .Net, Then Why Does Substring Take O(N) Time
How to Hide an Inherited Property in a Class Without Modifying the Inherited Class (Base Class)