public void RunTasksOnDifferentPartitionsInParallel()
            {
                var tasks         = new Task[200];
                var taskOrder     = new List <Int32>(tasks.Length);
                var tasksQueued   = new ManualResetEvent(false);
                var taskScheduler = new PartitionedTaskScheduler(task => task.AsyncState, 2, tasks.Length);

                for (var i = 0; i < tasks.Length; i++)
                {
                    tasks[i] = Task.Factory.StartNew(state =>
                    {
                        var taskId = (Int32)state;

                        lock (taskOrder)
                        {
                            taskOrder.Add(taskId);
                        }

                        tasksQueued.WaitOne();
                        Thread.Sleep(taskId % 3);
                    }, i, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning, taskScheduler);
                }

                tasksQueued.Set();

                Task.WaitAll(tasks);
                Assert.NotEqual(tasks.Length, taskOrder.Where((ordinal, index) => ordinal == index).Count());
            }
            public void BlockQueueUntilBelowBoundedCapacity()
            {
                var monitor       = new FakeMonitor();
                var threadPool    = new FakeThreadPool();
                var blocked       = new ManualResetEvent(false);
                var released      = new ManualResetEvent(false);
                var taskScheduler = new PartitionedTaskScheduler(_ => 0, 1, 1, threadPool, monitor);

                monitor.BeforeWait = () => blocked.Set();
                monitor.AfterPulse = () => released.Set();

                Task.Factory.StartNew(() =>
                {
                    // Schedule first task (non-blocking).
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);

                    // Schedule second task (blocking).
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);
                });

                // Wait for second task to be blocked.
                Assert.True(blocked.WaitOne(TimeSpan.FromMilliseconds(100)));
                Assert.Equal(1, threadPool.UserWorkItems.Count);

                threadPool.RunNext();

                // Wait for second task to be released.
                Assert.True(released.WaitOne(TimeSpan.FromMilliseconds(100)));

                threadPool.RunNext();

                Assert.Equal(0, taskScheduler.ScheduledTasks.Count());
            }
            public void WillDeadlockIfForceSynchronousExecutionsAcrossPartitions()
            {
                var tasksQueued      = new ManualResetEvent(false);
                var partition1Active = new ManualResetEvent(false);
                var partition2Active = new ManualResetEvent(false);
                var task1            = new Task(_ => { }, 1, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning);
                var task2            = new Task(_ => { }, 2, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning);
                var taskScheduler    = new PartitionedTaskScheduler(task => task.AsyncState, 2, 4);

                var task3 = Task.Factory.StartNew(_ =>
                {
                    tasksQueued.WaitOne();
                    partition1Active.Set();
                    partition2Active.WaitOne();
                    task1.RunSynchronously();
                }, 2, CancellationToken.None, TaskCreationOptions.LongRunning, taskScheduler);
                var task4 = Task.Factory.StartNew(_ =>
                {
                    tasksQueued.WaitOne();
                    partition2Active.Set();
                    partition1Active.WaitOne();
                    task2.RunSynchronously();
                }, 1, CancellationToken.None, TaskCreationOptions.LongRunning, taskScheduler);

                tasksQueued.Set();

                Assert.False(Task.WaitAll(new[] { task1, task2, task3, task4 }, 100));
            }
            public void BlockQueueUntilBelowBoundedCapacity()
            {
                var monitor = new FakeMonitor();
                var threadPool = new FakeThreadPool();
                var blocked = new ManualResetEvent(false);
                var released = new ManualResetEvent(false);
                var taskScheduler = new PartitionedTaskScheduler(_ => 0, 1, 1, threadPool, monitor);

                monitor.BeforeWait = () => blocked.Set();
                monitor.AfterPulse = () => released.Set();

                Task.Factory.StartNew(() =>
                {
                    // Schedule first task (non-blocking).
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);

                    // Schedule second task (blocking).
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);
                });

                // Wait for second task to be blocked.
                Assert.True(blocked.WaitOne(TimeSpan.FromMilliseconds(100)));
                Assert.Equal(1, threadPool.UserWorkItems.Count);

                threadPool.RunNext();

                // Wait for second task to be released.
                Assert.True(released.WaitOne(TimeSpan.FromMilliseconds(100)));

                threadPool.RunNext();

                Assert.Equal(0, taskScheduler.ScheduledTasks.Count());
            }
            public void RunAllTasksOnSamePartitionInOrder()
            {
                var tasks           = new Task[200];
                var taskGroup1Order = new List <Int32>();
                var taskGroup2Order = new List <Int32>();
                var tasksQueued     = new ManualResetEvent(false);
                var taskScheduler   = new PartitionedTaskScheduler(task => task.AsyncState, 2, tasks.Length);

                for (var i = 0; i < tasks.Length; i++)
                {
                    var taskGroupOrder = i % 2 == 0 ? taskGroup1Order : taskGroup2Order;
                    var taskId         = i;

                    tasks[taskId] = Task.Factory.StartNew(state =>
                    {
                        taskGroupOrder.Add(taskId);
                        tasksQueued.WaitOne();
                        Thread.Sleep(1);
                    }, taskId, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning, taskScheduler);
                }

                tasksQueued.Set();

                Task.WaitAll(tasks);
                Assert.Equal(tasks.Length / 2, taskGroup1Order.Where((ordinal, index) => ordinal == (index * 2)).Count());
                Assert.Equal(tasks.Length / 2, taskGroup2Order.Where((ordinal, index) => ordinal == (index * 2) + 1).Count());
            }
            public void RunOnDedicatedThreadIfLongRunning()
            {
                var isThreadPool  = false;
                var taskComplete  = new ManualResetEvent(false);
                var taskScheduler = new PartitionedTaskScheduler();

                Task.Factory.StartNew(() => { isThreadPool = Thread.CurrentThread.IsThreadPoolThread; taskComplete.Set(); }, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning, taskScheduler);

                Assert.True(taskComplete.WaitOne(TimeSpan.FromMilliseconds(100)));
                Assert.False(isThreadPool);
            }
            public void QueueImmediatelyIfBelowBoundedCapacity()
            {
                var taskScheduler = new PartitionedTaskScheduler(_ => 0, 1);
                var task          = Task.Factory.StartNew(() =>
                {
                    Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);
                });

                Assert.True(task.Wait(TimeSpan.FromMilliseconds(100)));
                Assert.Equal(0, taskScheduler.ScheduledTasks.Count());
            }
            public void AllowsInlineExecutionAfterBeingQueued()
            {
                var executions    = 0;
                var taskScheduler = new PartitionedTaskScheduler();
                var task          = new Task(() => { executions++; }, CancellationToken.None, TaskCreationOptions.AttachedToParent);

                task.RunSynchronously(taskScheduler);

                Assert.Equal(1, executions);
                Assert.Equal(0, taskScheduler.ScheduledTasks.Count());
            }
            public void QueueImmediatelyIfBelowBoundedCapacity()
            {
                var taskScheduler = new PartitionedTaskScheduler(_ => 0, 1);
                var task = Task.Factory.StartNew(() =>
                    {
                        Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);
                    });

                Assert.True(task.Wait(TimeSpan.FromMilliseconds(100)));
                Assert.Equal(0, taskScheduler.ScheduledTasks.Count());
            }
            public void WaitForPreceedingTasksIfRequired()
            {
                var executionOrder = new List <Int32>();
                var tasksQueued    = new ManualResetEvent(false);
                var taskScheduler  = new PartitionedTaskScheduler();

                Task.Factory.StartNew(() => { executionOrder.Add(0); tasksQueued.WaitOne(); Thread.Sleep(25); }, CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);
                Task.Factory.StartNew(() => executionOrder.Add(1), CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);

                var synchronousTask = new Task(() => executionOrder.Add(2), CancellationToken.None, TaskCreationOptions.AttachedToParent);

                tasksQueued.Set();
                synchronousTask.RunSynchronously(taskScheduler);

                Assert.Equal(3, executionOrder.Where((value, index) => value == index).Count());
            }
            public void RunOnDedicatedThreadIfLongRunning()
            {
                var isThreadPool = false;
                var taskComplete = new ManualResetEvent(false);
                var taskScheduler = new PartitionedTaskScheduler();

                Task.Factory.StartNew(() => { isThreadPool = Thread.CurrentThread.IsThreadPoolThread; taskComplete.Set(); }, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning, taskScheduler);

                Assert.True(taskComplete.WaitOne(TimeSpan.FromMilliseconds(100)));
                Assert.False(isThreadPool);
            }
            public void WaitForPreceedingTasksIfRequired()
            {
                var executionOrder = new List<Int32>();
                var tasksQueued = new ManualResetEvent(false);
                var taskScheduler = new PartitionedTaskScheduler();

                Task.Factory.StartNew(() => { executionOrder.Add(0); tasksQueued.WaitOne(); Thread.Sleep(25); }, CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);
                Task.Factory.StartNew(() => executionOrder.Add(1), CancellationToken.None, TaskCreationOptions.AttachedToParent, taskScheduler);

                var synchronousTask = new Task(() => executionOrder.Add(2), CancellationToken.None, TaskCreationOptions.AttachedToParent);

                tasksQueued.Set();
                synchronousTask.RunSynchronously(taskScheduler);

                Assert.Equal(3, executionOrder.Where((value, index) => value == index).Count());
            }
            public void AllowsInlineExecutionAfterBeingQueued()
            {
                var executions = 0;
                var taskScheduler = new PartitionedTaskScheduler();
                var task = new Task(() => { executions++; }, CancellationToken.None, TaskCreationOptions.AttachedToParent);

                task.RunSynchronously(taskScheduler);

                Assert.Equal(1, executions);
                Assert.Equal(0, taskScheduler.ScheduledTasks.Count());
            }
            public void WillDeadlockIfForceSynchronousExecutionsAcrossPartitions()
            {
                var tasksQueued = new ManualResetEvent(false);
                var partition1Active = new ManualResetEvent(false);
                var partition2Active = new ManualResetEvent(false);
                var task1 = new Task(_ => { }, 1, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning);
                var task2 = new Task(_ => { }, 2, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning);
                var taskScheduler = new PartitionedTaskScheduler(task => task.AsyncState, 2, 4);

                var task3 = Task.Factory.StartNew(_ =>
                    {
                        tasksQueued.WaitOne();
                        partition1Active.Set();
                        partition2Active.WaitOne();
                        task1.RunSynchronously();
                    }, 2, CancellationToken.None, TaskCreationOptions.LongRunning, taskScheduler);
                var task4 = Task.Factory.StartNew(_ =>
                    {
                        tasksQueued.WaitOne();
                        partition2Active.Set();
                        partition1Active.WaitOne();
                        task2.RunSynchronously();
                    }, 1, CancellationToken.None, TaskCreationOptions.LongRunning, taskScheduler);

                tasksQueued.Set();

                Assert.False(Task.WaitAll(new[] { task1, task2, task3, task4 }, 100));
            }
            public void RunTasksOnDifferentPartitionsInParallel()
            {
                var tasks = new Task[200];
                var taskOrder = new List<Int32>(tasks.Length);
                var tasksQueued = new ManualResetEvent(false);
                var taskScheduler = new PartitionedTaskScheduler(task => task.AsyncState, 2, tasks.Length);

                for (var i = 0; i < tasks.Length; i++)
                {
                    tasks[i] = Task.Factory.StartNew(state =>
                        {
                            var taskId = (Int32)state;

                            lock (taskOrder)
                            {
                                taskOrder.Add(taskId);
                            }

                            tasksQueued.WaitOne();
                            Thread.Sleep(taskId % 3);
                        }, i, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning, taskScheduler);
                }

                tasksQueued.Set();

                Task.WaitAll(tasks);
                Assert.NotEqual(tasks.Length, taskOrder.Where((ordinal, index) => ordinal == index).Count());
            }
            public void RunAllTasksOnSamePartitionInOrder()
            {
                var tasks = new Task[200];
                var taskGroup1Order = new List<Int32>();
                var taskGroup2Order = new List<Int32>();
                var tasksQueued = new ManualResetEvent(false);
                var taskScheduler = new PartitionedTaskScheduler(task => task.AsyncState, 2, tasks.Length);

                for (var i = 0; i < tasks.Length; i++)
                {
                    var taskGroupOrder = i % 2 == 0 ? taskGroup1Order : taskGroup2Order;
                    var taskId = i;

                    tasks[taskId] = Task.Factory.StartNew(state =>
                        {
                            taskGroupOrder.Add(taskId);
                            tasksQueued.WaitOne();
                            Thread.Sleep(1);
                        }, taskId, CancellationToken.None, TaskCreationOptions.AttachedToParent | TaskCreationOptions.LongRunning, taskScheduler);
                }

                tasksQueued.Set();

                Task.WaitAll(tasks);
                Assert.Equal(tasks.Length / 2, taskGroup1Order.Where((ordinal, index) => ordinal == (index * 2)).Count());
                Assert.Equal(tasks.Length / 2, taskGroup2Order.Where((ordinal, index) => ordinal == (index * 2) + 1).Count());
            }