The WaitMultiple
needs to be able to count on the WaitHandle
s not being garbage collected. If that were to occur, it would potentially end up with an access violation because of corrupt memory, or some similar nastiness.
The idea is that you should be able to call WaitMultiple
and destroy one or more of the WaitHandle
objects without WaitAny
failing. If it didn't create a copy, this would be impossible, and debugging that particular scenario would take you all day. So bottom line is that it's done for thread safety.
If you take a look at the documentation for the underlying native function, WaitForMultipleObjects, there is evidence of this: the behavior is described as undefined:
If one of these handles is closed while the wait is still pending, the function's behavior is undefined.
As suggested below, if it's important to squeeze all the performance you can out of it, you could ensure WaitHandles are not disposed, and make a p/invoke call to WaitForMultipleObjects. You can provide WaitHandle.SafeWaitHandle
as the handle to the synchronization object in question.
EDIT: The answer given above is wrong. I've come back to this question from time to time because it bothered me; I now believe I have a correct answer.
The purpose of this transfer of elements is thread-safe verification of individual WaitHandle
s. If the developer were to use the original array, it is possible that one of its elements could be overwritten with, say, a null
value, which would result in undefined behavior in the underlying native function. By copying the elements into an internal array, we can check each one, throw an exception if it's null
or otherwise invalid, and then store it. We know the internal array's elements can't be replaced. So for your long-ago purpose, you are fine if you aren't doing weird things like putting null or cross-AppDomain elements into your WaitHandle array.