Waiting for a Task to Complete and Getting Its Result

1. How to make wait a task for the completion?

2. How to handle the AggregateException?

3. What will happen if we don’t handle the AggregateException?

4. How to detect unobserved exceptions?

5. How to make wait completion of any or all tasks?

By using  Task.WaitAll, Task.WaitAny, Task.Wait  we can explicitly wait for a task to complete.

When a thread calls a Wait method the system checks whether the task has started and if it hasn’t the system may start (depending on the TaskScheduler) the task in the same thread.

Sample 1:

        static void Main(string[] args)

        {

            CancellationTokenSource cts = new CancellationTokenSource();

            Task<int> task = new Task<int>(n => DoSomeWork((int)n), 100, cts.Token, TaskCreationOptions.None);           

            task.Start();

            Task []waitTasks = new Task[2];

            waitTasks[0] = task;

            waitTasks[1] = task;

            Task.WaitAll(waitTasks, 1000, cts.Token);           

            TaskScheduler.UnobservedTaskException += new EventHandler<UnobservedTaskExceptionEventArgs>(TaskScheduler_UnobservedTaskException);

            try

            {

                Console.WriteLine(task.Result);

            }

            catch (AggregateException aggregateException)

            {

                aggregateException.Handle(

                    ex => {

                            Console.WriteLine(“Handled exception”);

                            Console.WriteLine(ex.Message);                           

                            return false;

                    }

                );           

                foreach (var exception in aggregateException.InnerExceptions)

                {                   

                    Console.WriteLine(exception.ToString());

                }

            }

            Console.ReadKey();

        }

        static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)

        {

            e.SetObserved();

        }

        private static int DoSomeWork(int n)

        {

            int sum = 1;

            Console.WriteLine(“Thread {0} started”, Thread.CurrentThread.ManagedThreadId);

            checked

            {

                for (int i = 0; i < n; i++)

                {

                    sum += sum;

                }

            }

            return sum;

        }

When a task throws an exception the exception will be swallowed and stored into collection of the AggregateException. The AggregateException will be thrown only when the method Wait will be called or the Result property will be invoked.

The AggregateException provides the Handle method which invokes a callback method for each exception stored in the AggregateException’s collection.

                aggregateException.Handle(

                    ex => {

                            Console.WriteLine(“Handled exception”);

                            Console.WriteLine(ex.Message);                           

                            return false;

                    }

                );           

If the code doesn’t invoke the Result or Wait’s methods the exceptions will be thrown only when the Finalize is called. We can subscribe to UnobservedTaskException

 TaskScheduler.UnobservedTaskException += new EventHandler<UnobservedTaskExceptionEventArgs>(TaskScheduler_UnobservedTaskException);

In case of calling the unobserved exception we can invoke the SetObserved() method to prevent terminating the program.

        static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)

        {

            e.SetObserved();

        }

There are methods WaitAll and WaitAny which allow us to wait for completion all or any tasks.