Myślę, że twoja metoda powinna działać poprawnie na piśmie.
wierzę, że WaitHandle.WaitAny() używa the Windows API function WaitForMultipleObjects(), dokumentacja dla których mówi:
Modyfikacja występuje jedynie dla obiektu lub obiektów, których stan sygnalizowany spowodował, że funkcja zwraca.
Jeśli jest to prawda, oznacza to, że kod powinien działać.
Napisałem program testowy. Tworzy ładunek AutoResetEvents i ustawia połowę z nich przed wywołaniem CancelableWaitAll(). Następnie rozpoczyna wątek, który czeka 5 sekund przed ustawieniem drugiej połowy AutoResetEvents. Natychmiast po uruchomieniu tego wątku główny wątek wywołuje funkcję CancelableWaitAll().
Jeśli funkcja WaitAny() rzeczywiście zresetuje jakiekolwiek zdarzenia z autoresetem inne niż ten, którego indeks został zwrócony, funkcja CancelableWaitAll() nigdy nie powróci.
Ponieważ ma powrócić (po 5 sekundach oczywiście), ja twierdząc, że kod działa z AutoResetEvents:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
public static class Program
{
private static void Main(string[] args)
{
AutoResetEvent[] events = new AutoResetEvent[32];
for (int i = 0; i < events.Length; ++i)
{
events[i] = new AutoResetEvent(false);
}
// Set the first 16 auto reset events before calling CancelableWaitAll().
for (int i = 0; i < 16; ++i)
{
events[i].Set();
}
// Start a thread that waits five seconds and then sets the rest of the events.
Task.Factory.StartNew(() => setEvents(events));
Console.WriteLine("Waiting for all events to be set.");
ManualResetEvent stopper = new ManualResetEvent(false);
CancelableWaitAll(events, stopper);
Console.WriteLine("Waited.");
}
private static void setEvents(AutoResetEvent[] events)
{
Thread.Sleep(5000);
for (int i = 16; i < events.Length; ++i)
{
events[i].Set();
}
}
public static bool CancelableWaitAll(WaitHandle[] waitHandles, WaitHandle cancelWaitHandle)
{
var waitHandleList = new List<WaitHandle>();
waitHandleList.Add(cancelWaitHandle);
waitHandleList.AddRange(waitHandles);
int handleIdx;
do
{
handleIdx = WaitHandle.WaitAny(waitHandleList.ToArray());
waitHandleList.RemoveAt(handleIdx);
}
while (waitHandleList.Count > 1 && handleIdx != 0);
return handleIdx != 0;
}
}
}
Niestety, nie mogę udowodnić, że WaitHandle.WaitAll() używa WaitForMultipleObjects (). Jeśli jednak nie, możesz wywołać to samodzielnie, używając funkcji WaitHandle.SafeWaitHandle, aby uzyskać obsługę zdarzeń systemu operacyjnego i użyć polecenia P/Invoke, aby wywołać funkcję WaitForMultipleObjects().
Spróbuj użyć jednej z przeciążonych metod. I spróbuj utworzyć tablicę przed wprowadzeniem do-go, może zyskasz nowe spostrzeżenia. –
Nie rozumiem, jak to zadziała, jeśli wydarzenie anulowania zostanie podniesione? – LukeHennerley
Jeśli wydarzenie anulowania zostanie podniesione, oczekiwanie na wszystkie podane waitHandles zostanie anulowane – Harry13