Home > front end >  When should you check Task.IsFaulted?
When should you check Task.IsFaulted?

Time:10-06

I found this code snippet (simplified version provided):

using System;
using System.Threading.Tasks;

namespace TaskTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var task = SendMessage();
            task.Wait();

            if (task.IsFaulted) // Never makes it to this line
            {
                Console.WriteLine("faulted!");
            }
            Console.Read();
        }

        private static async Task SendMessage()
        {
            await Task.Run(() => throw new Exception("something bad happened"));
        }
    }
}

I'm sure this is a bug since task.Wait(); throws and there is no catch block.

Now I'm wondering when you would need to use task.IsFaulted?

CodePudding user response:

The Task is throwing the exception, not the Task.Wait().

But there is a subtle way that exceptions get bubbled up when using Task.Wait() vs Task.GetAwaiter().GetResult()

You should probably use

task.GetAwaiter().GetResult();

See this question for a good explanation of how the different Syncronous ways to wait work with exceptions.

Task.IsFaulted is useful when using await Task.WhenAny(); or any other time where you want to check the status of a Task without awaiting it, eg from another synchronization context.

I often find myself using Task.IsCompleted | Faulted | Successful to determine what feedback to give a user in a WinForms scenario.

CodePudding user response:

When you await a Task asynchronously the program constantly switches between the calling context and the context of the awaited Task.(this is over generalized)

This means in SendMessage(); the program runs everything before the await call with the Main context, runs the awaited call in a Task, which may or may not run on another thread, and switched back to the original context of Main.

Because you awaited the Task within SendMessage(); the Task can properly bubble up errors to the calling context, which in this case is Main which halts the program.

Both .Wait() and await bubble errors back to the calling context.

In your example of you removed the .Wait();, the Task would run parallel (run synchronously in it's own context on another thread) and no errors would be able to bubble back to Main.

Think of it like you are cooking a two course meal. You could cook it asynchronously by constantly walking between two cooking stations and doing tasks at each a little at a time. Alternatively you could have a friend cook the other meal in parallel with you.

When you cook both meals yourself you will know immediately if you've burned your steak. But if you have your friend cook the steak, but he sucks at cooking steak, you won't know he's burned the steak until you check his work(.IsFaulted).

  • Related