This is already provided in .NET 4 with the Task.WaitAll(Task[], CancellationToken) method so make sure that you are not trying to reinvent the wheel.
If you cannot move to .NET 4 for some reason or are too committed to existing code that doesn't use the Task class then you can implement something similar to what Task.WaitAll() does. The basic scheme is that you just work down the list of WaitHandles and wait one each one in turn, using WaitAny() so you can also see the abort request. Like this:
/// <summary>
/// Wait for all events with option to abort the wait
/// </summary>
/// <param name="waitHandles">Synchronization objects to wait for</param>
/// <param name="abortEvent">Event that signals an abort</param>
/// <returns>false if the wait was aborted</returns>
public static bool WaitAll(WaitHandle[] waitHandles, WaitHandle abortEvent) {
WaitHandle[] pair = new WaitHandle[] { abortEvent, null };
for (int ix = 0; ix < waitHandles.Length; ++ix) {
pair[1] = waitHandles[ix];
if (WaitHandle.WaitAny(pair) == 0) return false;
}
return true;
}