Here I'm going to post whatever that is interesting for me. All things about programming using JavaScript and ASP.NET Core. And something else.

A blog about ASP.Net Core and JavaScript

A few days ago I noticed that I forgot some things about how to deal with System.Threading.Tasks.Task objects. So, I have decided to create a short document (or cheat sheet) to refresh Tasks in my memory. Maybe it will come in handy to someone else.

Overview

A task is a unit of work (in terms of Task Parallel Library).

The tasks are abstractions, the .NET way of grouping the unit of works together.

The Task object is typically executed asynchronously on a thread pool thread. So, use the Status, IsCanceled, IsCompleted, and IsFaulted properties, to determine the state of a task.

Creating and starting (running) tasks

There are a few ways of using tasks:

   Task.Factory.StartNew() creates and starts a Task. It's the preferred approach.

   var t = new Task(() => { ... }) creates a task. Use Task.Start() or Task.RunSynchronously() to fire it.

   var t2 = Task.Run{() => { ... }) creates and runs a task.  It's the preferred approach too.

Tasks take an optional object argument:

   Task.Factory.StartNew(x => { foo(x) }, arg);

To return values, use generic Task<TResult> instead of Task.

To get the returned value, use Task<TResult>.Result property. This waits until the task is complete.

Use Task.CurrentId to identify individual tasks.

Canceling tasks

Use CancellationTokenSource and CancellationToken.

var cts = new CancellationTokenSource();
var token = cts.Token;
var t = new Task(() =>
{
    int i = 0;
    while (true)
    {
        if (token.IsCancellationRequested)
        {
            // release resources, if any...
            // I) Soft Exit
            // break;// task cancellation is cooperative, no-one kills your thread
            // II) Canonical (hard) exit 1. Exception is not propagated.
            throw new OperationCanceledException();
        }
        // III) Canonical (hard) exit 2. Short version of II)
        // token.ThrowIfCancellationRequested();
        Console.WriteLine(i++);
    }
}, token);
t.Start();

Task.Factory.StartNew(() =>
{
    token.WaitHandle.WaitOne();
    Console.WriteLine("Wait handle released, thus cancellation was requested");
});

Console.ReadKey();
cts.Cancel();//cancelling task
Thread.Sleep(1000); // cancellation is non-instant

 

Use CancellationTokenSource.CreateLinkedTokenSource() to create a composite token source.

var cts1 = new CancellationTokenSource();
var cts2 = new CancellationTokenSource();
var compositeCts = CancellationTokenSource.CreateLinkedTokenSource(
    cts1.Token, cts2.Token);
var token = compositeCts.Token;
//use token in tasks
cts1.Cancel();//cancelling task
//or
//cts2.Cancel();

 

Waiting for time to pass

Use Thread.Sleep() or CancellationToken.WaitHandle.WaitOne() to switch the context and suspend the current task thread. The task thread will not be scheduled for execution by the operating system.

Use Thread.SpinWait() or SpinWait.SpinUntil() to avoid the context switch and to keep the task thread in the thread scheduler.

Waiting for tasks

Use Task.Wait() to wait for the task to complete execution. It returns true if the task finished its execution in the specified time interval.

Use Task.WaitAll(Task[]) to wait for all of the provided Task objects to complete execution.

Use Task.WaitAny(Task[]) to wait for any of the provided Task objects to complete execution.

Task exceptions handling

Task exception is ignored completely in the main ( task parent) thread if an exception is not handled inside tasks.

To observe exceptions in the main thread,  use,  for example, Task.WaitAll().

Catch AggregateException and:

  or