Content:
1. Task
2. async - await
   - Run async, return a value and wait
   - Run async, return a value and do NOT wait
   - Worker method without await
   - Does not run async even if marked as async and called with await
3. Calling asynchronously a method that is not marked with async from an async
4. Updating UI from methods executed on another thread
5. Canceling running task


This article describes Task class and async - await concept. Available in Visual Studio 2012 and newer.

Code examples


1. Task

Here is MSDN Task description (with example)
Basically, Task is class that represents a task running on (typically) another (worker) thread.

Create task

C#
private void LongTaskNoParam()
{
    // do something here
}

Task task1 = new Task(LongTaskNoParam);
task1.Start();
Create task with factory

C#
Task task2 = Task.Factory.StartNew(LongTaskNoParam);
Passing parameter to the task

C#
private void LongTaskParam(object myParam)
{
    // do something here
}

Task task3 = Task.Factory.StartNew(LongTaskParam, 3000);
Waiting for the task.
UI will be blocked if you wait in the same method.
Note: You can limit execution by timeout or pass cancellation token.

C#
task3.Wait();
Running task on the same thread.
Be aware that you can start one task only once.

C#
Task task4 = new Task(LongTaskNoParam);
task4.RunSynchronously();

2. async - await

This concept simplifies calling long running method that would prevent user from interaction with the UI.

Read first this brief explanation with a good example of async on MSDN page.

In order to execute a method asynchronously:
1. The method has to be marked with async
2. Return type must be Task<>
3. If the caller needs to wait until async call finishes, use await
4. await can be used only inside a method marked as async
5. In order to run asynchronously, the method marked as async has to call another async method or Task.Run
6. async methods cannot have out or ref parameters

MSDN
Asynchronous Programming with Async and Await
Control flow in async programs
await

Run async, return a value and wait

In this example, the code will run "in order", but will not block UI. Outup of log() statements will be in ascending order. All the calls of Log() will be made on the same thread. See code examples with thread ids in output.

C#
public async Task<string> RunsAsynchronously(int sleepTime)
{
    Log("1"); 
    await Task.Delay(sleepTime);
    Log("2"); // start + sleep time
    return " Finished Async";
}

private async void button1_Click(object sender, EventArgs e)
{
    string s = await RunsAsynchronously(3000);
    Log("3"); // start + sleep time
}

Run async, return a value and do NOT wait

In this example, only the RunsAsynchronously() method will wait, button1_Click() method will not wait and flow will continue immediately after RunsAsynchronously() was launched, because await in front of RunsAsynchronously is missing.

C#
public async Task<string> RunsAsynchronously(int sleepTime)
{
    Log("2"); 
    await Task.Delay(sleepTime);
    Log("3"); 
    return " Finished Async";
}

private async void button1_Click(object sender, EventArgs e)
{
    RunsAsynchronously(3000);  // cannot assign result "string s = " without "await"
    Log("1");  // start RunsAsynchronously() and continues 
}

Worker method without await

In this example, only the button1_Click() method will wait until RunsAsynchronously() completes, but RunsAsynchronously() will not wait for Task.Delay() completion and button1_Click will continue immediately after call returnes from RunsAsynchronously() (before Task.Delay() call completes).

C#
public async Task<string> RunsAsynchronously(int sleepTime)
{
    Log("1"); 
    Task.Delay(sleepTime); // will not wait here without "await"
    Log("2"); // Log("1") + 0.01sec
    return " Finished Async";
}

private async void button1_Click(object sender, EventArgs e)
{
    string s = await RunsAsynchronously(3000);
    Log("3");  // Log("2") + 0.01s time 
}

Does not run async even if marked as async and called with await

because WillNotRunAsync() does not have any method with await. This will block UI.

C#
public async Task<string> WillNotRunAsync()
{
    Thread.Sleep(2000);  // simulates long running method
    return "Did not run async";
}

Task<string> result = await WillNotRunAsync();
because WillNotRunAsync does not call another async method.


3. Calling asynchronously a method that is not marked with async from an async

You have certainly a lot of long running methods that are not marked as async in your code base. In order to call them asynchronously, you can create a wrapper async method

C#
private string LongTaskWithResult()
{
    Thread.Sleep(5000);
    return "LongTaskWithResult";
}

private async Task<string> LongTaskWithResultAsync()
{
    string s = await Task.Factory.StartNew(() => LongTaskWithResult());
    return s;
}
...

string s = await LongTaskWithResultAsync(); 
or call it directly, if the caller is marked as async

C#
string s = await Task.Factory.StartNew(() => LongTaskWithResult());
In both cases, the caller has to be a method marked with async.

In order to call a non async method from another non async method, you need to mark the anonymous method as async

C#
string s;
Task.Factory.StartNew(async () => 
{ 
    s = await LongTaskWithResultAsync();
    // here the code waits 
    DoSomething();
});
// here the code does NOT wait 

4. Updating UI from methods executed on another thread

If you need to update UI, e.g. set a Textbox value, if you try doing this from another than UI thread, you will get "cross thread operation not valid" error. To be able to update UI from non UI thread, you need to use SynchronizationContext

C#
using System.Threading;
....

SynchronizationContext m_syncContext; 
SendOrPostCallback m_UIUpdateMethod;

public MyForm()
{
    m_syncContext = SynchronizationContext.Current; // stores main thread context
    m_UIUpdateMethod = UIUpdateMethod;
}

private void UIUpdateMethod(object state)
{
   textBox1.Text += (string)state;
}

public async Task MyAsynchronousMethod()
{
    m_syncContext.Post(m_UIUpdateMethod, "Hello from MyAsynchronousMethod()"); 
}

5. Canceling running task

It is useful to provide an option to cancel a long running task. Here is how you can do it.

C#
private void LongTask(CancellationToken ct)
{
    for (int i=0; i < 100; i++)
    {
        if (ct.IsCancellationRequested)
        {
            return;
        }
        else
        {
            // Do something
        }
    }
}

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;
Task.Factory.StartNew(() => LongTask(ct), ct);

...
cts.Cancel();  // cancel when needed