I can't find any documentation for the behaviour of Task.WaitAny()
under the following scenarios:
My assumption would be that 2 & 3 would return immediately (#3 picking an arbitrary index to return, likely the first or last one depending on implementation detail but not guaranteed.) and I'd sorta expect 1 to return true?
Some brief unit tests seem to confirm this... the following all pass. If anyone can find some formal documentation of this behaviour, I'd be glad to see it. (Even if only to improve my ability to locate it myself next time!)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using System.Threading;
namespace TANTest.Threading
{
[TestFixture]
public class MetaTaskTests
{
private const int SafeTimeOutMillisecs = 1000;
[Test, Timeout(SafeTimeOutMillisecs)]
public void Meta_NewTaskCompletes()
{
var task = new Task(() => { });
task.Start();
Thread.Sleep(10);
Assert.That(task.IsCompleted, Is.True);
}
[Test, Timeout(SafeTimeOutMillisecs)]
public void Meta_EmptySetOfTasks_WaitsProceed()
{
var tasks = new List<Task>();
Task.WaitAny(tasks.ToArray());
Task.WaitAll(tasks.ToArray());
}
[Test, Timeout(SafeTimeOutMillisecs)]
public void Meta_EmptySetOfTasks_WaitsGiveExpectedOutputs()
{
var tasks = new List<Task>();
Assert.That(Task.WaitAny(tasks.ToArray(), TimeSpan.FromMilliseconds(100)), Is.EqualTo(-1));
Assert.That(Task.WaitAll(tasks.ToArray(), TimeSpan.FromMilliseconds(100)), Is.True);
}
[Test, Timeout(SafeTimeOutMillisecs)]
public void Meta_SetOfCompletedTasks_WaitsProceed()
{
var tasks = new List<Task>
{
new Task(() => { }),
new Task(() => { })
};
tasks.ForEach(task => task.Start());
Thread.Sleep(10);
Task.WaitAny(tasks.ToArray());
Task.WaitAll(tasks.ToArray());
}
[Test, Timeout(SafeTimeOutMillisecs)]
public void Meta_SetOfCompletedTasks_WaitsGiveExpectedOutputs()
{
var tasks = new List<Task>
{
new Task(() => { }),
new Task(() => { })
};
tasks.ForEach(task => task.Start());
Thread.Sleep(10);
Assert.That(Task.WaitAny(tasks.ToArray(), TimeSpan.FromMilliseconds(100)), Is.GreaterThan(-1));
Assert.That(Task.WaitAll(tasks.ToArray(), TimeSpan.FromMilliseconds(100)), Is.True);
}
[Test, Timeout(SafeTimeOutMillisecs)]
public void Meta_SetOfUnstartedTasks_WaitsDontProceed()
{
var tasks = new List<Task>
{
new Task(() => { }),
new Task(() => { })
};
Thread.Sleep(10);
Assert.That(Task.WaitAny(tasks.ToArray(), TimeSpan.FromMilliseconds(100)), Is.EqualTo(-1));
Assert.That(Task.WaitAll(tasks.ToArray(), TimeSpan.FromMilliseconds(100)), Is.False);
}
[Test, Timeout(SafeTimeOutMillisecs)]
public void Meta_SetOfTasksWithOneCompleted_AnyProceedsAndOutputsIndex()
{
var tasks = new List<Task>
{
new Task(() => { }),
new Task(() => { })
};
tasks.First().Start();
Thread.Sleep(10);
Assert.That(Task.WaitAny(tasks.ToArray()), Is.GreaterThan(-1));
}
[Test, Timeout(SafeTimeOutMillisecs)]
public void Meta_SetOfTasksWithOneCompleted_AllTimesOutWithExpectedOutput()
{
var tasks = new List<Task>
{
new Task(() => { }),
new Task(() => { })
};
tasks.First().Start();
Thread.Sleep(10);
Assert.That(Task.WaitAll(tasks.ToArray(), TimeSpan.FromMilliseconds(100)), Is.False);
}
}
}