Synchronous and Asynchronous, Parallel and Concurrency in C# (Application Examples)

Foreword: This article only shows some simple examples of C# multithreading, for reference purposes only. The underlying principles of multithreading are discussed in subsequent articles.

Basic concept:

Synchronous and asynchronous

What is the difference between sync and async c#? It can be understood that synchronization and asynchronousness are the ultimate goal, and threads are a way to achieve them.

There are two main points to note about thread synchronization: order and consistency.

  • Order: Refers to the order in which programs are executed. For example, in single-threaded programming, A(); B(); , must wait for the A method to be executed, and the B method can be executed. For another example, lock(sync){A();}, no matter how many threads call this code, the A method only allows one thread to call at the same time, and other threads must wait.
  • Consistency: Primarily to ensure data consistency, it must be ensured that changes to critical section data do not affect other threads. For example, the A thread and the B thread modify the data for a certain period of time. In order to avoid the latter modification to cover the situation of the former modification, we lock the modification of the data, so that data will only allow one thread to modify at a time, which ensures the consistency of the data.

In fact, in the processing of multi-threading problems, we are seeking the purpose of synchronization in asynchronous to ensure the security of the program.

Windows 10 Pro Key + Microsoft Office Professional Plus 2016 Key (Value Package)

Parallelism and concurrency

Let’s take an image metaphor to explain these two terms:

  • Two teams, enter a door, each team turns into one each time, which is called concurrency.
  • Two teams entered two doors respectively. Each enters each door, which is called parallelism.

Multithreading in C#, the use of Thread

static void Main(string[] args)
        {
            Thread th = new Thread(new ThreadStart(SayHello));
            Thread th1 = new Thread(new ParameterizedThreadStart(SayHi));

            th.Start();
            th1.Start("XXX");

            th.Join();
            th1.Join();

            Console.WriteLine("all child thread end...");
        }

        private static void SayHello()
        {
            Console.WriteLine("hello");
        }

        private static void SayHi(object o)
        {
            Console.WriteLine("hi " + o);
        }

Use of ThreadPool

  • Advantages: You can achieve higher execution efficiency by reusing threads (the cost of creating threads is relatively high, and each thread takes up about 1MB of memory)
  • Disadvantages:
    1. Job execution time using thread pool is shorter
    2. Unable to get a reference to the thread being executed in the thread pool, so the thread could not be managed. For example, there is no way to know when the thread ends.
static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(SayHello);
            ThreadPool.QueueUserWorkItem(SayHello, "XX");
            Thread.Sleep(2000);
        }

        private static void SayHello(object state)
        {
            Console.WriteLine($"thread ID : {Thread.CurrentThread.ManagedThreadId}" + $" hi,{state}");
        }

The use of Task

Task call with no return value

Console.WriteLine($"current ID: {Thread.CurrentThread.ManagedThreadId} : Hello");

            Task task =Task.Run(() =>
            {
                Console.WriteLine($"current ID: {Thread.CurrentThread.ManagedThreadId} : Hello");
            });

            task.Wait();

Task call with return value

static void Main(string[] args)
        {
            Task<bool> task = Task.Run(() =>
            {
                return true;
            });

            task.Wait();

            System.Console.WriteLine(task.Result);
        }

Task continuation

Task continuations can be used to establish a task chain with a pre-relationship

static void Main(string[] args)
        {
            Console.WriteLine($"current ID: {Thread.CurrentThread.ManagedThreadId} : Hello");

            Task task =Task.Run(() =>
            {
                Console.WriteLine($"current ID: {Thread.CurrentThread.ManagedThreadId} : Hello");
            });

            Task taskA = task.ContinueWith((preTask) =>
            {
                Trace.Assert(preTask.Status == TaskStatus.RanToCompletion);
                Console.WriteLine("taskA ...");
            },TaskContinuationOptions.OnlyOnRanToCompletion);

            Task taskB = task.ContinueWith((preTask) =>
            {
                Trace.Assert(preTask.Status == TaskStatus.Canceled);
                Console.WriteLine("taskB...");
            },TaskContinuationOptions.OnlyOnCanceled);

            Task taskC = task.ContinueWith((preTask) =>
            {
                Trace.Assert(preTask.Status == TaskStatus.Faulted);
                Console.WriteLine("taskC...");
            },TaskContinuationOptions.OnlyOnFaulted);

            Thread.Sleep(5000);

        }

Exception handling during the use of Task

static void Main(string[] args)
        {
            Task task = Task.Run(() =>
            {
                throw new InvalidOperationException();
            });

            try
            {
                task.Wait();

            }
            catch (AggregateException ex)
            {
                ex.Handle((eachException) =>
                {
                    Console.WriteLine(eachException.Message);
                    return true;
                });
            }
        }

Cancel Task

static void Main(string[] args)
        {
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            cancellationTokenSource.Token.Register(() =>
            {
                Console.WriteLine("cancel callback");
            });
            Task task = Task.Run(() =>
            {
                while (!cancellationTokenSource.Token.IsCancellationRequested)
                {
                   // Console.Write("-");
                }

                Console.WriteLine("cancel task ....");
            },cancellationTokenSource.Token);

            Console.WriteLine("Push any key to Cancel task!");
            Console.ReadKey();
            cancellationTokenSource.Cancel();
            task.Wait();
        }

Create long-running tasks

static void Main(string[] args)
        {
            Task task = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("this is long long time task...");
            }, TaskCreationOptions.LongRunning);

            task.Wait();
        }

Use of asyn and await

static void Main(string[] args)
        {
            Task task = DownloadDataAsyn();
            task.Wait();
        }

        public static async Task DownloadDataAsyn()
        {
            string url = "https://www.google.com";
            WebRequest webRequest = WebRequest.Create(url);
            WebResponse webResponse = await webRequest.GetResponseAsync();
            using (StreamReader sr = new StreamReader(webResponse.GetResponseStream()))
            {
                string text = await sr.ReadToEndAsync();
                Console.WriteLine("size: " + text.Length);
            }
        }