2

I have an application that need control many slave processes to do the task. And there is a matching thread to do the match job. I use EventWaitHandle to communicate between them, at free time the matching thread is wait for slave's event, the code is like:

EventWaitHandle.WaitAny(GetWaitEvents());
//GetWaitEvents method will return all slave process's EventWaitHandle

In the slave process, once it is free. It will trigger the event to match another task to this process. Code like:

ProxyEvent.Set()

However, when the number of the event exceed 64, it will throw System.NotSupportedException. After checking the code get from the Microsoft, I found it is hard code in the framwork code:

private const int MAX_WAITHANDLES = 64;

My question is:

  1. Why it have such limit? Why 64?
  2. Is there any workaound for this limit?
2power10
  • 1,259
  • 1
  • 11
  • 33
  • Have a look at http://stackoverflow.com/questions/2702545/workaround-for-the-waithandle-waitall-64-handle-limit – V4Vendetta May 20 '13 at 09:20
  • 1
    Maybe instead of using threads you can do it with `Task`s? They will work fine in many cases, are easy to use and lighter on system as well – Jarek May 20 '13 at 09:25
  • If you can give us more details about what you want to achieve, maybe we can come up with alternative approaches. – Matthew Watson May 20 '13 at 09:28

2 Answers2

3

The reason for 64 is that is the number of bits in a word on a 64-bit processor.

The implementation uses bit flags to make it as fast as possible.

The workarounds differ depending on what you're trying to do. See for example Workaround for the WaitHandle.WaitAll 64 handle limit? as mentioned by V4Vendetta.

One workaround I've used is to create split the wait handles into two arrays, and then use one thread to wait for one of the arrays and another thread to wait for the other. Then the main thread waits for either of those threads. This isn't very nice though, because it uses an entire extra thread.

(My actual implementation of this was more complicated that the explanation above implies. I had to restrict the number of wait handles to 63 in each array because I needed the extra one to stop the "other" thread waiting when one of them finished waiting on the array.)

The MSDN documentation for WaitForMultipleObjects() does mention a couple of workarounds:

Create a thread to wait on MAXIMUM_WAIT_OBJECTS handles, then wait on that thread plus the other handles. Use this technique to break the handles into groups of MAXIMUM_WAIT_OBJECTS.

Call RegisterWaitForSingleObject to wait on each handle. A wait thread from the thread pool waits on MAXIMUM_WAIT_OBJECTS registered objects and assigns a worker thread after the object is signaled or the time-out interval expires.

(I used the first approach in the past, but I have long since rewritten that code to use IO completion ports instead.)

Community
  • 1
  • 1
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
3

The Why? Is reasonably easily answered once you realise that it's inherited from WaitForMultipleObjects. It, in turn, has a limit, because the return value from the function attempts to encode multiple facts into a single integer, and so they picked a practical value that should accommodate most situations.

And I'd agree with @Pako's comment - it's pretty likely that running (more than) 64 threads probably isn't the best approach - if they're all active and you have less than 64 cores, you're probably swamping the system and its wasting time performing context switches when it could be performing useful work.

Using e.g. Tasks or the TPL will allow your code to scale gracefully with the amount of work it can actually perform.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448