Tag Archives: Exception

Multithreading

Multithreading becomes absolutely necessary as soon as you start working with GUI. You cannot let the system freeze and your users asking themselves if the program crashed each time you let a long operation run, that is why you should call async methods. An async method has to declare await in order to free the main thread, otherwise it will run synchronously.

Starting an asynchronous task

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting Main");

            AsyncMethod("AsyncTask1");
            AsyncMethod("AsyncTask2");

            Console.WriteLine("Main Thread continues doing something else");
            Thread.Sleep(2000);

            Console.WriteLine("Leaving Main");
        }

        private static async Task AsyncMethod(string message)
        {
            await Task.Run(() => LongSyncRunningMethod(message));
        }

        private static void LongSyncRunningMethod(string message)
        {
            Console.WriteLine($"Starting {message}");
            Thread.Sleep(1000);
            Console.WriteLine($"{message} done");
        }
    }
}

One might instinctively think, that LongSyncRunningMethod and its Console.WriteLine($"Starting {message}"); would be called before Console.WriteLine("Main Thread continues doing something else"); but it actually depends on the task scheduler. In some cases it will be true, in other cases not.

Starting Main
Starting AsyncTask1
Main Thread continues doing something else
Starting AsyncTask2
AsyncTask1 done
AsyncTask2 done
Leaving Main

Starting an asynchronous task and getting a return value

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting Main");

            AsyncCalculation();

            Console.WriteLine("Main Thread continues doing something else");
            Thread.Sleep(2000);

            Console.WriteLine("Leaving Main");
        }

        private static async Task AsyncCalculation()
        {
            int result = await Task.Run(() => LongCalculation());
            Console.WriteLine($"Calculated value: {result}");
        }

        private static int LongCalculation()
        {
            Thread.Sleep(1000);
            return 101;
        }
    }
}
Starting Main
Starting AsyncCalculation
Main Thread continues doing something else
Calculated value: 101
Leaving Main

Catching Exception in an asynchronous task

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting Main");

            AsyncExceptionMethod();

            Console.WriteLine("Main Thread continues doing something else");
            Thread.Sleep(2000);

            Console.WriteLine("Leaving Main");
        }

        private static async Task AsyncExceptionMethod()
        {
            await Task.Run(() => ThrowException())
                .ContinueWith(task => HandleTaskException(task));
        }

        private static void ThrowException()
        {
            throw new Exception();
        }

        private static void HandleTaskException(Task task)
        {
            if (task.Exception != null)
            {
                Console.WriteLine("Exception caught");
            }
        }
    }
}
Starting Main
Starting AsyncExceptionMethod
Main Thread continues doing something else
Exception caught
Leaving Main

As the task run in another thread, a thrown exception will not be caught in the main thread. The method ContinueWith allows the user to run a check after the task is completed and handle accordingly. In this case ContinueWith accepts a lambda expression with Task as parameter, we can check the status of the completed task, for example if it was completed, cancelled or faulted.

await Task.Run(() => LongCalculation)
    .ContinueWith(task =>
{
    if (task.IsCanceled)
        DoSomethingWhenCancelled();
    else if (task.IsFaulted)
        DoSomethingOnError(task .Exception);
    else 
        // task.IsCompleted
        DoSomethingWhenComplete();
});

https://blog.stephencleary.com/2012/02/async-and-await.html

https://johnthiriet.com/removing-async-void/

Advertisement