Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of C # Multithreading related Operations

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly introduces the example analysis of C# multithreading related operations, which has a certain reference value. Interested friends can refer to it. I hope you will gain a lot after reading this article.

Thread exception

We can use try-catch to catch exceptions in a single thread, as shown in the following code:

Using System;namespace MultithreadingOption {class Program {static void Main (string [] args) {# region single thread catch exception try {int [] array = {1, 23, 61, 678, 23, 45}; Console.WriteLine (array [6]) } catch (Exception ex) {Console.WriteLine ($"message: {ex.Message}");} # endregion Console.ReadKey ();}}

The result of running the program:

So how do you catch exceptions in multithreading? Is it also possible to use try-catch for capture? Let's look at the following code first:

Using System;using System.Threading.Tasks;namespace MultithreadingOption {class Program {static void Main (string [] args) {# region single thread catch exception / / try / / {/ int [] array = {1, 23, 61, 678, 23, 45}; / / Console.WriteLine (array [6]) / /} / / catch (Exception ex) / / {/ / Console.WriteLine ($"message: {ex.Message}"); / / exception try {for (int I = 0; I) in # endregion # region multithreading

< 30; i++) { string str = $"main_{i}"; // 开启线程 Task.Run(() =>

{Console.WriteLine ($"{str} started"); if (str.Equals ("main_5")) {throw new Exception ("main_5 exception") } else if (str.Equals ("main_11")) {throw new Exception ("main_11 has an exception") } else if (str.Equals ("main_18")) {throw new Exception ("an exception occurred in main_18");} Console.WriteLine ($"{str} ended") });}} catch (Exception ex) {Console.WriteLine ($"message: {ex.Message}");} # endregion Console.ReadKey ();}

The result of running the program:

We see that no exception information is output in the result, is there no exception thrown? Let's debug the code and look at the debugging information:

We see that an exception is indeed thrown in the program, but the program does not catch it, so where does the exception go? The exception is swallowed by multithreading, so how to catch the exception in multithreading? What if you write try-catch in a thread? Each thread is single-threaded, so there is no point in writing try-catch in each thread. To catch an exception in multithreading, you need to use WaitAll (). Look at the following code:

Try {/ / defines a List collection of type Task List taskList = new List (); for (int I = 0; I

< 30; i++) { string str = $"main_{i}"; // 开启线程,并把线程添加到集合中 taskList.Add(Task.Run(() =>

{Console.WriteLine ($"{str} started"); if (str.Equals ("main_5")) {throw new Exception ("main_5 exception") } else if (str.Equals ("main_11")) {throw new Exception ("main_11 has an exception") } else if (str.Equals ("main_18")) {throw new Exception ("an exception occurred in main_18");} Console.WriteLine ($"{str} ended");})) } / / wait for all threads to finish executing Task.WaitAll (taskList.ToArray ());} catch (Exception ex) {Console.WriteLine ($"message: {ex.Message}");}

We debug with code, and debug the results:

At this point, we can enter the catch. We monitor the ex and find that ex is an exception of type AggregateException. We are further optimizing the code:

Try {/ / defines a List collection of type Task List taskList = new List (); for (int I = 0; I

< 30; i++) { string str = $"main_{i}"; // 开启线程,并把线程添加到集合中 taskList.Add(Task.Run(() =>

{Console.WriteLine ($"{str} started"); if (str.Equals ("main_5")) {throw new Exception ("main_5 exception") } else if (str.Equals ("main_11")) {throw new Exception ("main_11 has an exception") } else if (str.Equals ("main_18")) {throw new Exception ("an exception occurred in main_18");} Console.WriteLine ($"{str} ended");})) } / / wait for all threads to finish executing Task.WaitAll (taskList.ToArray ());} catch (AggregateException are) {foreach (var exception in are.InnerExceptions) {Console.WriteLine (exception.Message);}} catch (Exception ex) {Console.WriteLine ($"message: {ex.Message}");}

Finally, run the program:

We find that the specific abnormal information can be captured at this time.

II. Thread cancellation

In the above example, we caught the exception that occurred in multithreading and also output the exception information, but this is unfriendly. In actual development, we use multiple threads to execute tasks concurrently. If one of the tasks fails or has an exception, we want to be able to tell the other threads to stop, so what should we do? At this point, you need to use thread cancellation.

Task cannot terminate the task externally, it can only terminate itself.

The .net framework provides the CancellationTokenSource class, which has a property of type bool: IsCancellationRequested, which defaults to false, indicating whether to cancel the thread. There is also a Cancel () method that sets the property value of IsCancellationRequested to true and cannot be set back. The code is as follows:

/ / instantiate object CancellationTokenSource cts = new CancellationTokenSource (); for (int I = 0; I

< 20; i++){ string str = $"main_{i}"; // 开启线程 Task.Run(() =>

{try {Console.WriteLine ($"{str} started"); / / pause Thread.Sleep (new Random (). Next (50,100) * 100) If (str.Equals ("main_5")) {throw new Exception ("main_5 exception");} else if (str.Equals ("main_11")) {throw new Exception ("main_11 exception") } if (cts.IsCancellationRequested = = false) {Console.WriteLine ($"{str} ended");} else {Console.WriteLine ($"{str} thread cancel") }} catch (Exception ex) {/ / an exception occurred. Set the value of IsCancellationRequested to true cts.Cancel (); Console.WriteLine ($"message: {ex.Message}");}});}

The result of running the program:

As you can see, when an exception occurs, some threads are canceled. In this way, the thread cancellation is initially implemented.

In the above example, we start the thread first and cancel the thread if an exception occurs. Then there will be such a situation: there is an exception in the thread, and some threads may not be opened at this time, so can we not let these threads open? The Run method of Task has one overload:

The second parameter indicates that the thread is canceled. And this parameter happens to be in the CancellationTokenSource class:

Therefore, we can use the overload of the Run method not to open the thread, as follows:

Try {/ / instantiate the object CancellationTokenSource cts = new CancellationTokenSource (); / / create a collection of type Task List taskList = new List (); for (int I = 0; I

< 20; i++) { string str = $"main_{i}"; // 开启线程 Task.run 以后 添加Token 就可以在某一个线程发生异常之后,让没有开启的线程不开启了 taskList.Add(Task.Run(() =>

{try {Console.WriteLine ($"{str} started"); / / pause Thread.Sleep (new Random (). Next (50,100) * 10) If (str.Equals ("main_5")) {throw new Exception ("main_5 exception");} else if (str.Equals ("main_11")) {throw new Exception ("main_11 exception") } if (cts.IsCancellationRequested = = false) {Console.WriteLine ($"{str} ended");} else {Console.WriteLine ($"{str} thread cancel") }} catch (Exception ex) {/ / an exception occurred, set the value of IsCancellationRequested to true cts.Cancel ();}}, cts.Token);} / wait for all threads to finish executing Task.WaitAll (taskList.ToArray ()) } catch (AggregateException are) {foreach (var exception in are.InnerExceptions) {Console.WriteLine (exception.Message);}}

The result of running the program:

There is a sentence in the output: a task has been cancelled, but there is no print in our code. Where did this come from? This is because of the second parameter Token, after adding this parameter, if there is an exception on the thread, it will not continue to start the thread.

III. Temporary variables

Let's first take a look at the following code:

For (int I = 0; I

< 20; i++){ // 开启线程 Task.Run(() =>

{Task.Run (()) = > Console.WriteLine ($"this is {I} ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString (" 00 ")}");});}

What is the output of this code? We run the program to see the results:

Some people may wonder why the output is always 20 instead of the value of each loop. What is the reason for this. This is because there is no blocking when we apply for the thread, and execution is delayed. We know that the execution speed of the code is very fast, the loop 20 times is completed almost instantly, this is I becomes 20, but the thread is delayed execution, when the thread actually executes, it corresponds to the same I, and then I is 20, so the output is 20. So how do you output the value of each loop? Look at the following code:

For (int I = 0; I

< 20; i++){ // 定义一个新的变量 int k = i; // 开启线程 Task.Run(() =>

{Task.Run (()) = > Console.WriteLine ($"this is {I} _ {k} ThreadId: {Thread.CurrentThread.ManagedThreadId.ToString (" 00 ")}");});}

The result of running the program:

In this way, in each loop, the variable k is redefined to ensure that it is new each time, so the value of k is the value of each loop.

IV. Thread safety

What is thread safety? Thread safety: if your code has multiple threads running at the same time in the process, it is thread safe if the result of each run is consistent with that of a single thread.

Under what circumstances will the problem of thread safety arise?

Generally speaking, there are global variables / shared variables / static variables / hard disk files / database values, as long as multi-thread access and modification, there will be thread safety problems. Look at the following code:

Int syncNum = 0nint AsyncNum = 0bot for (int I = 0There I)

< 10000; i++){ syncNum++;}Console.WriteLine($"syncNum={syncNum}"); //单线程10000 10000for (int i = 0; i < 10000; i++){ Task.Run(() =>

{AsyncNum++;});} Console.WriteLine ($"AsyncNum = {AsyncNum}")

The result of running the program:

This is the problem caused by thread safety. So how to solve this problem? At this point, you can use the lock keyword to solve it. The lock keyword is defined as follows:

Private static readonly object Form_Lock = new object (); / / the standard way to write lock objects

Modify the code as follows:

Int syncNum = 0nint AsyncNum = 0bot for (int I = 0There I)

< 10000; i++){ syncNum++;}Console.WriteLine($"syncNum={syncNum}");for (int i = 0; i < 10000; i++){ Task.Run(() =>

{lock (Form_Lock) {AsyncNum++;}});} / / hibernate for 5 seconds, waiting for all threads to finish executing Thread.Sleep (5000); Console.WriteLine ($"AsyncNum = {AsyncNum}")

The result of running the program:

In addition to using lock, we can also use data splitting to avoid multithreading the same data, which is safe and efficient.

Thank you for reading this article carefully. I hope the article "sample Analysis of C# Multithreading related Operations" shared by the editor will be helpful to everyone. At the same time, I also hope that you will support and pay attention to the industry information channel. More related knowledge is waiting for you to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report