This is a series of articles about Multi-threading.

Introduction

The first article in this series, Multi-Threading (1), Concept: What, Why, written on 01/30/2023, introduced the multi-threading concept. The following articles should be the implementations of different approaches.

I used to plan to start from the original approach, the delegate implementation, then go to Asynchronous Programming Model (APM), Event-based Asynchronous Pattern (EAP), and Asynchronous Programming Model (APM). However, due to being busy with something else, I did not have much time to think about this topic; I even lost the logical clue of this series of articles. Occasionally, I saw one piece of notes, an interview question about multi-threading, very interesting, that leads to this article.

The async and await keywords, although they have been used in C# for more than 10 years, this implementation is a very new approach, quite different from the traditional one. Probably, just due to this reason, I may start from here, introducing the async and await and the newest implementation approach, without the impression from the old approaches; that might be a good approach because if someone jumps into the programming world, the C# world, they might not know the traditional implementation approaches. Let us start from here.

I will use the interview question as an example to discuss the async and await keywords and the multi-threading program in C# in detail.

The content of the article,

The next article, Multi-Threading (3-1), async, multi-await, will give more example analysis from different angles.

Problem

We start with the interview question: how to get the expected output:

Hello World

By one of three workflows:

(1)

Workflow

(2)

(3)

"async" and "await" Key Words in C#

async and await are two new keywords introduced into C# 5.0 in 2012. At that time, CPU clock speed reached an upper limit imposed by physical laws. But chip makers started to deliver CPUs with several cores that can run tasks in parallel. Thus C# needed a way to ease asynchronous programming.

The "async" keyword marks a method asynchronous, meaning it can be run in the background while another code executes. When you mark a method as async, you can use the "await" keyword to indicate that the method should wait for the result of an asynchronous operation before continuing.

Code sample

public async Task<int> ExampleMethodAsync()
{
    var httpClient = new HttpClient();
    int exampleInt = (await httpClient.GetStringAsync("http://msdn.microsoft.com")).Length;
    ResultsTextBox.Text += "Preparing to finish ExampleMethodAsync.\n";
    // After the following return statement, any method that's awaiting
    // ExampleMethodAsync (in this case, StartButton_Click) can get the
    // integer result.
    return exampleInt;
}

async in C#

await in C#

The async and await keywords are the heart of async programming. By using those two keywords, one can create an asynchronous method almost as easily as creating a synchronous method, even without really understanding the runtime workflow.

Note

Highlighting Main, we get the warning message

warning CS1998: This async method lacks ‘await’ operators and will run synchronously. Consider using the ‘await’ operator to await non-blocking API calls or ‘await Task.Run(…)’ to do CPU-bound work on a background thread.

warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the await operator to the result of the call.

Thread Flow Analyses

(1) ---

The output:

The code running flow according to the output:

As shown in the screenshot above:

once the keyword await is met for the first time in the main thread, 1, at Line 45,

where the main thread,1, is in RED, while the async thread, 4, is in GREEN.

(2) ---

The output:

The code running flow according to the output:

As shown in the screenshot above:

once the keyword await is met for the first time in the main thread, 1, at Line 45,

where the main thread,1, is in RED, while the async thread, 4, is in GREEN.

(3) ---

The output:

The code running flow according to the output:

As shown in the screenshot above:

once the keyword await is met for the first time in the main thread, 1, at Line 45,

where the main thread,1, is in RED, while the async thread, 4, is in GREEN.

Solution: --- (3)

(1)

Output:

(2)

Output:

(3)

Output:

Synchronous Process

If we do not define any await within the async methods:

the program will be exactly the same as the synchronous process:

and the running flow is actually the same as the full async process:

Output:

References: