Esempio n. 1
0
        // [Fact(Skip = "outerloop")]
        public void RunConcurrentExclusiveSchedulerPairTests()
        {
            // Validate invalid arguments
            {
                Assert.Throws <ArgumentNullException>(() => new ConcurrentExclusiveSchedulerPair(null));
                Assert.Throws <ArgumentOutOfRangeException>(() => new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, -2));
                Assert.Throws <ArgumentOutOfRangeException>(() => new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 0));
                Assert.Throws <ArgumentOutOfRangeException>(() => new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 1, -2));
                Assert.Throws <ArgumentOutOfRangeException>(() => new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 1, 0));
            }

            // Validate completion prevents more tasks
            {
                bool localPassed = true;
                ConcurrentExclusiveSchedulerPair cesp = new ConcurrentExclusiveSchedulerPair();
                cesp.Complete();
                Assert.Throws <TaskSchedulerException>(() => Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, cesp.ConcurrentScheduler).Wait());
                Assert.Throws <TaskSchedulerException>(() => Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, cesp.ExclusiveScheduler).Wait());
                Assert.True(localPassed, string.Format("{0}: Completion prevents more tasks", localPassed ? "Success" : "Failure"));
            }

            // Validate completion allows existing scheduled tasks to complete
            {
                bool localPassed = true;
                ConcurrentExclusiveSchedulerPair cesp = new ConcurrentExclusiveSchedulerPair();
                int tasksToSchedule = 2;
                int count           = 0;
                var tasks           = new Task[tasksToSchedule];
                using (var mres = new ManualResetEventSlim())
                {
                    for (int i = 0; i < tasksToSchedule; i++)
                    {
                        tasks[i] = Task.Factory.StartNew(() =>
                        {
                            mres.Wait();
                            Interlocked.Increment(ref count);
                        }, CancellationToken.None, TaskCreationOptions.None, cesp.ExclusiveScheduler);
                    }
                    cesp.Complete();
                    Assert.True(count == 0, "No tasks should have completed yet");
                    mres.Set();
                    Task.WaitAll(tasks);
                    Assert.True(count == tasksToSchedule, "All of the tasks should have executed");
                    cesp.Completion.Wait();
                }
                Assert.True(localPassed, string.Format("{0}: Completion allows existing tasks to complete", localPassed ? "Success" : "Failure"));
            }

            //  Validate MCL handling
            {
                bool localPassed = true;
                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(new ControllableMclTaskScheduler(4), 8);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == 4;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(new ControllableMclTaskScheduler(8), 4);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == 4;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, -1);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == Int32.MaxValue;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(new ControllableMclTaskScheduler(-2), -1);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == Int32.MaxValue;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(new ControllableMclTaskScheduler(-2), 1);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == 1;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                Assert.True(localPassed, string.Format("{0}: Max Concurrency Level corner cases handling correctly", localPassed ? "Success" : "Failure"));
            }

            // Validate queueing when layering on a faulty scheduler
            {
                bool localPassed = true;
                var  ts          = new ControllableTaskScheduler();

                // NOTE: We're using new pair instances on each iteration to avoid code paths
                // where a replica task gets queued up in the scheduler.  If that happens while the underlying
                // scheduler is FailQueueing==true, the task used internally by CESP will fault
                // and will go unobserved.  This is by design and we don't want it bringing down the tests.
                var cesp1 = new ConcurrentExclusiveSchedulerPair(ts);
                var cesp2 = new ConcurrentExclusiveSchedulerPair(ts);
                foreach (var cesp in new[] { cesp1, cesp2 })
                {
                    var scheduler = cesp == cesp1 ? cesp1.ConcurrentScheduler : cesp2.ExclusiveScheduler;

                    // Queue a task that will cause the CESP to fail queueing to its underlying scheduler
                    ts.FailQueueing = true;
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, scheduler);

                    try
                    {
                        Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, scheduler);
                        localPassed = false;
                    }
                    catch (Exception exc)
                    {
                        Assert.True(
                            exc is TaskSchedulerException && ((TaskSchedulerException)exc).InnerException is InvalidOperationException,
                            "Expected a TaskSchedulerException containing an InvalidOperationException");
                    }

                    Assert.True(SpinWait.SpinUntil(() => cesp.Completion.IsCompleted, 1), "Excepted CESP to complete in allotted time");
                    Assert.True(cesp.Completion.Exception != null, "Excepted CESP task to have exceptions");
                }

                Assert.True(localPassed, string.Format("{0}: Test queueing layering on faulty scheduler", localPassed ? "Success" : "Failure"));
            }

            // Validate inlining when layering on a faulty scheduler
            {
                bool localPassed = true;
                var  ts          = new ControllableTaskScheduler();

                // NOTE: We're using new pair instances on each iteration to avoid code paths
                // where a replica task gets queued up in the scheduler.  If that happens while the underlying
                // scheduler is FailQueueing==true, the task used internally by CESP will fault
                // and will go unobserved.  This is by design and we don't want it bringing down the tests.
                var cesp1 = new ConcurrentExclusiveSchedulerPair(ts);
                var cesp2 = new ConcurrentExclusiveSchedulerPair(ts);
                foreach (var cesp in new[] { cesp1, cesp2 })
                {
                    var scheduler = cesp == cesp1 ? cesp1.ConcurrentScheduler : cesp2.ExclusiveScheduler;

                    // Inline a task that will cause the CESP to fail queueing to its underlying scheduler
                    ts.FailQueueing = false;
                    Task.Factory.StartNew(() =>
                    {
                        ts.FailQueueing = true;
                        Task t          = new Task(() => { });
                        try
                        {
                            t.RunSynchronously(scheduler);
                            localPassed = false;
                        }
                        catch (Exception exc)
                        {
                            Assert.True(
                                exc is TaskSchedulerException && ((TaskSchedulerException)exc).InnerException is TaskSchedulerException,
                                "Excepted a TaskSchedulerException to contain another TaskSchedulerException");
                        }
                        Assert.True(t.IsCompleted, "Expected the queued task to be completed");
                        Assert.True(t.Exception != null, "Expected the queued task to be faulted");
                    }, CancellationToken.None, TaskCreationOptions.None, scheduler).Wait();

                    ts.FailQueueing = false;
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, scheduler).Wait();
                    cesp.Complete();

                    Assert.True(SpinWait.SpinUntil(() => cesp.Completion.IsCompleted, 1), "Expected the CESP to complete in the allotted time");
                    Assert.True(cesp.Completion.Exception == null, "Expected the task to not be faulted and have no exceptions");
                }

                Assert.True(localPassed, string.Format("{0}: Test inlining layering on faulty scheduler", localPassed ? "Success" : "Failure"));
            }

            // Validate tasks on the same scheduler waiting on each other
            {
                bool localPassed = true;
                foreach (var underlyingScheduler in new[] { TaskScheduler.Default, new ControllableTaskScheduler()
                                                            {
                                                                FailQueueing = false
                                                            } })
                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(underlyingScheduler);
                    TaskRecursion(2, new ParallelOptions {
                        TaskScheduler = cesp.ExclusiveScheduler
                    });
                    cesp.Complete();

                    cesp = new ConcurrentExclusiveSchedulerPair(underlyingScheduler);
                    TaskRecursion(2, new ParallelOptions {
                        TaskScheduler = cesp.ConcurrentScheduler
                    });
                    cesp.Complete();
                }
                Assert.True(localPassed, string.Format("{0}: Recursively waiting on same scheduler", localPassed ? "Success" : "Failure"));
            }

            // Exercise additional inlining code paths
            {
                bool localPassed = true;
                foreach (var underlyingScheduler in new[] { TaskScheduler.Default, new ControllableTaskScheduler()
                                                            {
                                                                FailQueueing = false
                                                            } })
                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(underlyingScheduler);
                    Task.Factory.StartNew(() => { }).ContinueWith(_ => { }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, cesp.ExclusiveScheduler).Wait();
                    Task.Factory.StartNew(() => { }).ContinueWith(_ => { }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, cesp.ConcurrentScheduler).Wait();

                    var t = new Task(() => { });
                    t.RunSynchronously(cesp.ConcurrentScheduler);
                    t.Wait();

                    t = new Task(() => { });
                    t.RunSynchronously(cesp.ExclusiveScheduler);
                    t.Wait();

                    Task.Factory.StartNew(() =>
                    {
                        new Task(() => { }, TaskCreationOptions.AttachedToParent).RunSynchronously(cesp.ConcurrentScheduler);
                    }, CancellationToken.None, TaskCreationOptions.None, cesp.ConcurrentScheduler).Wait();

                    Task.Factory.StartNew(() =>
                    {
                        new Task(() => { }, TaskCreationOptions.AttachedToParent).RunSynchronously(cesp.ExclusiveScheduler);
                    }, CancellationToken.None, TaskCreationOptions.None, cesp.ExclusiveScheduler).Wait();
                }
                Assert.True(localPassed, string.Format("{0}: Additional inlining code paths", localPassed ? "Success" : "Failure"));
            }
        }
        public void RunConcurrentExclusiveSchedulerPairTests()
        {
            // Validate invalid arguments
            {
                Assert.Throws<ArgumentNullException>(() => new ConcurrentExclusiveSchedulerPair(null));
                Assert.Throws<ArgumentOutOfRangeException>(() => new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, -2));
                Assert.Throws<ArgumentOutOfRangeException>(() => new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 0));
                Assert.Throws<ArgumentOutOfRangeException>(() => new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 1, -2));
                Assert.Throws<ArgumentOutOfRangeException>(() => new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, 1, 0));
            }

            // Validate completion prevents more tasks
            {
                bool localPassed = true;
                ConcurrentExclusiveSchedulerPair cesp = new ConcurrentExclusiveSchedulerPair();
                cesp.Complete();
                Assert.Throws<TaskSchedulerException>(() => Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, cesp.ConcurrentScheduler).Wait());
                Assert.Throws<TaskSchedulerException>(() => Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, cesp.ExclusiveScheduler).Wait());
                Assert.True(localPassed, string.Format("{0}: Completion prevents more tasks", localPassed ? "Success" : "Failure"));
            }

            // Validate completion allows existing scheduled tasks to complete
            {
                bool localPassed = true;
                ConcurrentExclusiveSchedulerPair cesp = new ConcurrentExclusiveSchedulerPair();
                int tasksToSchedule = 2;
                int count = 0;
                var tasks = new Task[tasksToSchedule];
                using (var mres = new ManualResetEventSlim())
                {
                    for (int i = 0; i < tasksToSchedule; i++)
                    {
                        tasks[i] = Task.Factory.StartNew(() =>
                        {
                            mres.Wait();
                            Interlocked.Increment(ref count);
                        }, CancellationToken.None, TaskCreationOptions.None, cesp.ExclusiveScheduler);
                    }
                    cesp.Complete();
                    Assert.True(count == 0, "No tasks should have completed yet");
                    mres.Set();
                    Task.WaitAll(tasks);
                    Assert.True(count == tasksToSchedule, "All of the tasks should have executed");
                    cesp.Completion.Wait();
                }
                Assert.True(localPassed, string.Format("{0}: Completion allows existing tasks to complete", localPassed ? "Success" : "Failure"));
            }

            //  Validate MCL handling
            {
                bool localPassed = true;
                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(new ControllableMclTaskScheduler(4), 8);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == 4;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(new ControllableMclTaskScheduler(8), 4);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == 4;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, -1);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == Int32.MaxValue;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(new ControllableMclTaskScheduler(-2), -1);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == Int32.MaxValue;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(new ControllableMclTaskScheduler(-2), 1);
                    localPassed &= cesp.ConcurrentScheduler.MaximumConcurrencyLevel == 1;
                    localPassed &= cesp.ExclusiveScheduler.MaximumConcurrencyLevel == 1;
                }

                Assert.True(localPassed, string.Format("{0}: Max Concurrency Level corner cases handling correctly", localPassed ? "Success" : "Failure"));
            }

            // Validate queueing when layering on a faulty scheduler
            {
                bool localPassed = true;
                var ts = new ControllableTaskScheduler();

                // NOTE: We're using new pair instances on each iteration to avoid code paths
                // where a replica task gets queued up in the scheduler.  If that happens while the underlying
                // scheduler is FailQueueing==true, the task used internally by CESP will fault
                // and will go unobserved.  This is by design and we don't want it bringing down the tests.
                var cesp1 = new ConcurrentExclusiveSchedulerPair(ts);
                var cesp2 = new ConcurrentExclusiveSchedulerPair(ts);
                foreach (var cesp in new[] { cesp1, cesp2 })
                {
                    var scheduler = cesp == cesp1 ? cesp1.ConcurrentScheduler : cesp2.ExclusiveScheduler;

                    // Queue a task that will cause the CESP to fail queueing to its underlying scheduler
                    ts.FailQueueing = true;
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, scheduler);

                    try
                    {
                        Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, scheduler);
                        localPassed = false;
                    }
                    catch (Exception exc)
                    {
                        Assert.True(
                            exc is TaskSchedulerException && ((TaskSchedulerException)exc).InnerException is InvalidOperationException,
                            "Expected a TaskSchedulerException containing an InvalidOperationException");
                    }

                    Assert.True(SpinWait.SpinUntil(() => cesp.Completion.IsCompleted, 1), "Excepted CESP to complete in allotted time");
                    Assert.True(cesp.Completion.Exception != null, "Excepted CESP task to have exceptions");
                }

                Assert.True(localPassed, string.Format("{0}: Test queueing layering on faulty scheduler", localPassed ? "Success" : "Failure"));
            }

            // Validate inlining when layering on a faulty scheduler
            {
                bool localPassed = true;
                var ts = new ControllableTaskScheduler();

                // NOTE: We're using new pair instances on each iteration to avoid code paths
                // where a replica task gets queued up in the scheduler.  If that happens while the underlying
                // scheduler is FailQueueing==true, the task used internally by CESP will fault
                // and will go unobserved.  This is by design and we don't want it bringing down the tests.
                var cesp1 = new ConcurrentExclusiveSchedulerPair(ts);
                var cesp2 = new ConcurrentExclusiveSchedulerPair(ts);
                foreach (var cesp in new[] { cesp1, cesp2 })
                {
                    var scheduler = cesp == cesp1 ? cesp1.ConcurrentScheduler : cesp2.ExclusiveScheduler;

                    // Inline a task that will cause the CESP to fail queueing to its underlying scheduler
                    ts.FailQueueing = false;
                    Task.Factory.StartNew(() =>
                    {
                        ts.FailQueueing = true;
                        Task t = new Task(() => { });
                        try
                        {
                            t.RunSynchronously(scheduler);
                            localPassed = false;
                        }
                        catch (Exception exc)
                        {
                            Assert.True(
                                exc is TaskSchedulerException && ((TaskSchedulerException)exc).InnerException is TaskSchedulerException,
                                "Excepted a TaskSchedulerException to contain another TaskSchedulerException");
                        }
                        Assert.True(t.IsCompleted, "Expected the queued task to be completed");
                        Assert.True(t.Exception != null, "Expected the queued task to be faulted");
                    }, CancellationToken.None, TaskCreationOptions.None, scheduler).Wait();

                    ts.FailQueueing = false;
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, scheduler).Wait();
                    cesp.Complete();

                    Assert.True(SpinWait.SpinUntil(() => cesp.Completion.IsCompleted, 1), "Expected the CESP to complete in the allotted time");
                    Assert.True(cesp.Completion.Exception == null, "Expected the task to not be faulted and have no exceptions");
                }

                Assert.True(localPassed, string.Format("{0}: Test inlining layering on faulty scheduler", localPassed ? "Success" : "Failure"));
            }

            // Validate tasks on the same scheduler waiting on each other
            {
                bool localPassed = true;
                foreach (var underlyingScheduler in new[] { TaskScheduler.Default, new ControllableTaskScheduler() { FailQueueing = false } })
                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(underlyingScheduler);
                    TaskRecursion(2, new ParallelOptions { TaskScheduler = cesp.ExclusiveScheduler });
                    cesp.Complete();

                    cesp = new ConcurrentExclusiveSchedulerPair(underlyingScheduler);
                    TaskRecursion(2, new ParallelOptions { TaskScheduler = cesp.ConcurrentScheduler });
                    cesp.Complete();
                }
                Assert.True(localPassed, string.Format("{0}: Recursively waiting on same scheduler", localPassed ? "Success" : "Failure"));
            }

            // Exercise additional inlining code paths
            {
                bool localPassed = true;
                foreach (var underlyingScheduler in new[] { TaskScheduler.Default, new ControllableTaskScheduler() { FailQueueing = false } })
                {
                    var cesp = new ConcurrentExclusiveSchedulerPair(underlyingScheduler);
                    Task.Factory.StartNew(() => { }).ContinueWith(_ => { }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, cesp.ExclusiveScheduler).Wait();
                    Task.Factory.StartNew(() => { }).ContinueWith(_ => { }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, cesp.ConcurrentScheduler).Wait();

                    var t = new Task(() => { });
                    t.RunSynchronously(cesp.ConcurrentScheduler);
                    t.Wait();

                    t = new Task(() => { });
                    t.RunSynchronously(cesp.ExclusiveScheduler);
                    t.Wait();

                    Task.Factory.StartNew(() =>
                    {
                        new Task(() => { }, TaskCreationOptions.AttachedToParent).RunSynchronously(cesp.ConcurrentScheduler);
                    }, CancellationToken.None, TaskCreationOptions.None, cesp.ConcurrentScheduler).Wait();

                    Task.Factory.StartNew(() =>
                    {
                        new Task(() => { }, TaskCreationOptions.AttachedToParent).RunSynchronously(cesp.ExclusiveScheduler);
                    }, CancellationToken.None, TaskCreationOptions.None, cesp.ExclusiveScheduler).Wait();
                }
                Assert.True(localPassed, string.Format("{0}: Additional inlining code paths", localPassed ? "Success" : "Failure"));
            }
        }