public void DependentParallelTask()
        {
            // Reset the counter, the tasks will update this.
            Thread.VolatileWrite(ref _counter, 0);

            // Create an boundary that will ensure all tasks complete before exiting.
            using (TaskBoundary boundary = new TaskBoundary())
            {
                // Create two tasks...
                ParallelTask firstTask = new ParallelActionWrapper<ThreadPoolExecutionStrategy>(this.WaitForTwoSeconds);
                ParallelTask secondTask = new ParallelActionWrapper<ThreadPoolExecutionStrategy>(this.WaitForTwoSeconds);
                Assert.IsTrue(firstTask.IsIdle);
                Assert.IsTrue(secondTask.IsIdle);

                // Start the first task, it will take 2 seconds to complete.
                firstTask.AsyncExecute();
                Assert.IsTrue(firstTask.IsPending | firstTask.IsExecuting, "task state should be Pending or Executing");
                Assert.IsTrue(secondTask.IsIdle, "task state should be Idle");

                // Schedule the second task to start when the first task completes.
                //   The timeout is set to 10 seconds just in case the first task
                //   fails to complete. You can also use Timeout.Infinite.
                secondTask.ScheduledExecute(firstTask, TimeSpan.FromSeconds(10));
                Assert.IsTrue(secondTask.IsPending | secondTask.IsExecuting, "task state should be Pending or Executing");
                Assert.IsTrue(secondTask.IsScheduled | secondTask.IsExecuting, "task state should be Scheduled or Executing");

                // We should get here in milliseconds, so the counter should not
                // be incremented yet. If it is then one of the above calls was
                // a blocking call, which is an error.
                Assert.AreEqual(0, Thread.VolatileRead(ref _counter), "Counter should not have incremented already");

                // Wait for the second task to complete. This will take slightly
                // longer than 4 seconds.
                secondTask.WaitForCompletion();
                Assert.IsTrue(firstTask.IsCompletedSuccess);
                Assert.IsTrue(secondTask.IsCompletedSuccess);

                boundary.MarkCompleted();
            }
            // And now the counter should have been incremented by both tasks.
            Assert.AreEqual(2, Thread.VolatileRead(ref _counter));
        }
 private void FireAndForget()
 {
     ParallelTask task = new ParallelActionWrapper<ThreadPoolExecutionStrategy>(this.WaitForTwoSeconds);
     task.AsyncExecute();
     new ParallelActionWrapper<ThreadPoolExecutionStrategy>(this.WaitForTwoSeconds).ScheduledExecute(task, Timeout.Infinite);
 }
        public void IndependentParallelTask()
        {
            // Reset the counter, the tasks will update this.
            Thread.VolatileWrite(ref _counter, 0);

            // Create and execute one task that waits two seconds before it completes.
            ParallelTask task = new ParallelActionWrapper<ThreadPoolExecutionStrategy>(this.WaitForTwoSeconds);
            Assert.IsTrue(task.IsIdle);
            task.AsyncExecute();
            Assert.IsTrue(task.IsPending | task.IsExecuting, "task state should be Pending or Executing");

            // We should get here in milliseconds, so the counter should not
            // be incremented yet. If it is then one of the above calls was
            // a blocking call, which is an error.
            Assert.AreEqual(0, Thread.VolatileRead(ref _counter), "Counter should not have incremented already");

            // Wait for the task to complete.
            task.WaitForCompletion();
            Assert.IsTrue(task.IsCompletedSuccess);

            // And now the counter should have been incremented by the task.
            Assert.AreEqual(1, Thread.VolatileRead(ref _counter));
        }
        public void IndependentParallelTask_FireAndForget()
        {
            // Reset the counter, the tasks will update this.
            Thread.VolatileWrite(ref _counter, 0);

            using (TaskBoundary boundary = new TaskBoundary())
            {
                // Create and execute one task that waits two seconds before it completes.
                ParallelTask task = new ParallelActionWrapper<ThreadPoolExecutionStrategy>(this.FireAndForget);
                Assert.IsTrue(task.IsIdle);
                task.AsyncExecute();
                Assert.IsTrue(task.IsPending | task.IsExecuting, "task state should be Pending or Executing");

                // The counter will increment after the fire and forget tasks execute.
                Assert.AreEqual(0, Thread.VolatileRead(ref _counter), "Counter should not have incremented already");

                // Wait for the task to complete.
                task.WaitForCompletion();
                Assert.IsTrue(task.IsCompletedSuccess);

                boundary.MarkCompleted();
            }
            // And now the counter should have been incremented by the two fire and forget tasks.
            Assert.AreEqual(2, Thread.VolatileRead(ref _counter));
        }
        public void DependentParallelTask_SecondTaskTimeoutBeforeFirstTaskCompletes()
        {
            // Reset the counter, the tasks will update this.
            Thread.VolatileWrite(ref _counter, 0);

            try
            {
                // Create an boundary that will ensure all tasks complete before exiting.
                using (TaskBoundary boundary = new TaskBoundary())
                {
                    // Create two tasks...
                    ParallelTask firstTask = new ParallelActionWrapper<ThreadPoolExecutionStrategy>(this.WaitForTwoSeconds);
                    ParallelTask secondTask = new ParallelActionWrapper<ThreadPoolExecutionStrategy>(this.WaitForTwoSeconds);
                    Assert.IsTrue(firstTask.IsIdle);
                    Assert.IsTrue(secondTask.IsIdle);

                    // Schedule the second task to start when the first task completes.
                    //   The timeout is set to 1 second so that it times out before
                    //   the first task completes.
                    secondTask.ScheduledExecute(firstTask, TimeSpan.FromSeconds(1));
                    Assert.IsTrue(secondTask.IsPending, "task state should be Pending");
                    Assert.IsTrue(secondTask.IsScheduled, "task state should be Scheduled");
                    Assert.IsTrue(firstTask.IsIdle);

                    // Start the first task, it will take 2 seconds to complete.
                    firstTask.AsyncExecute();
                    Assert.IsTrue(firstTask.IsPending | firstTask.IsExecuting, "task state should be Pending or Executing");

                    // We should get here in milliseconds, so the counter should not
                    // be incremented yet. If it is then one of the above calls was
                    // a blocking call, which is an error.
                    Assert.AreEqual(0, Thread.VolatileRead(ref _counter), "Counter should not have incremented already");

                    try
                    {
                        // Wait for the second task to complete. This will take slightly
                        // longer than 1 second and a TimeoutException is thrown.
                        secondTask.WaitForCompletion();
                        Assert.Fail("The dependent task should have thrown an ParallelTimeoutException");
                    }
                    finally
                    {
                        // We expected the error and want the first task to complete.
                        boundary.MarkCompleted();
                    }
                }
            }
            catch (ParallelTimeoutException)
            {
                // And now the counter should have been incremented by the first task before
                // exiting the boundary.
                Assert.AreEqual(1, Thread.VolatileRead(ref _counter));
                throw;
            }
        }