First thing first, we should have basic understanding of difference between asynchronous programming and multithreading?. Please go through it as it will clear some of the questions on your mind.

Here is an analogy that may help understand the problem. You are cooking in a restaurant. An order comes in for eggs and toast.

So in brief, Threading is about workers, Asynchronous is about tasks.

In this article, I've tried to solve the common problem of working with a public list or a resource using asynchronous calls in a multi-threaded program. I have demonstrated same problem with a use case where I will create 2 users and they will run multiple threads and simultaneously will read and print public list on console.

We follow these simple steps,
  1. Create a public list that has to be shared by multiple users running on separate threads.
  2. Creating multiple users
  3. Running each user on a separate thread
  4. Asynchronous call to print method where we have implemented different time delay’s for each user to simulate real-time scenario of asynchronous calls.

Here , I have created separate methods to simplify my task and for better understanding of code.

Step 1

We will start by creating a list that will be shared by multiple users. Then we will call CreateUsers().
  1. class Program {
  2. public static List < string > UserList;
  3. static void Main(string[] args) {
  4. Console.WriteLine("Main Thread Id - {0}", Thread.CurrentThread.ManagedThreadId);
  5. UserList = new List < string > ();
  6. UserList.Add("A");
  7. UserList.Add("B");
  8. UserList.Add("C");
  9. UserList.Add("D");
  10. UserList.Add("E");
  11. UserList.Add("F");
  12. UserList.Add("G");
  13. UserList.Add("H");
  14. CreateUsers();
  15. Console.WriteLine("Completed main thread !!");
  16. Console.ReadKey();
  17. }
  18. }
Step 2
In this method, we can read users data from a .csv file or database and based on their count. We can create different threads for them by passing their object to the next method, i.e createthread().
  1. private static void CreateUsers() {
  2. Console.WriteLine();
  3. Console.WriteLine("Creating user() Thread Id - {0}", Thread.CurrentThread.ManagedThreadId);
  4. //here we can read users data from csv file or database and based on their count we can create different threads for them
  5. // by passing their object to next method i.e createthread().
  6. for (int i = 0; i < 2; i++) {
  7. // here i am assuming I have 2 users count and I am passing i counter variable ->as their unique Id
  8. //which can be used to print threads-id with the ID of user.
  9. int tempUser = i;
  10. createThread(tempUser);
  11. }
  12. }
Step 3
Here we will create a separate thread for each user and pass user data to Print() method.
  1. private static void createThread(int tempUser) {
  2. Console.WriteLine();
  3. Console.WriteLine("createthread() Thread Id - {0} for user id - {1} ", Thread.CurrentThread.ManagedThreadId, tempUser);
  4. new Thread(() => Print(tempUser)).Start();
  5. }
Step 4
This Print() will call asynchronous method and will wait before printing its completion message to console. Notice this method will be running on separate threads simultaneously.
  1. private static void Print(int tempUser) {
  2. Console.WriteLine();
  3. Console.WriteLine("Print() Thread Id - {0} for user id - {1} ", Thread.CurrentThread.ManagedThreadId, tempUser);
  4. new Program().Print_success(tempUser).Wait();
  5. Console.WriteLine("printing for user {0} completed with Thread id- {1} !!", tempUser, Thread.CurrentThread.ManagedThreadId);
  6. }
Step 5
Now we will create our Asynchronous Print_Success() that performs task of printing data from the list and here to demonstrate different delays in real-time async tasks we will make our threads sleep for different duration’s.
  1. public async Task Print_success(int tempUser) {
  2. Console.WriteLine();
  3. Console.WriteLine("Print_success() Thread Id - {0} for user id - {1} ", Thread.CurrentThread.ManagedThreadId, tempUser);
  4. await Task.Run(() => {
  5. foreach(var item in UserList) {
  6. if (tempUser == 0) {
  7. Thread.Sleep(10000);
  8. Console.WriteLine("User: {0} says- {1} on Thread ID - {2}", tempUser, item, Thread.CurrentThread.ManagedThreadId);
  9. } else {
  10. Thread.Sleep(5000);
  11. Console.WriteLine("User: {0} says- {1} on Thread ID - {2}", tempUser, item, Thread.CurrentThread.ManagedThreadId);
  12. }
  13. }
  14. });
  15. }

Output

  1. In Output, we print Thread Id of main() and other functions that we have called.
  2. We can notice that our functions before calling new thread() that have same thread Id but once new thread() is called functions after that are running on separate thread ID’s
  3. We can also see delay in our output from asynchronous Print_Success() call.
Asynchronous, Multi-Threaded Programming With Example In C#