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 Thread synchronization in C # Multithreading

2025-04-09 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

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

This article will explain in detail the example analysis of thread synchronization in C# multithreading. The editor thinks it is very practical, so I share it with you for reference. I hope you can get something after reading this article.

I. Preface

Let's first look at the following example:

Using System;using System.Threading;namespace ThreadSynchDemo {class Program {private static int Counter = 0; static void Main (string [] args) {Thread T1 = new Thread (() = > {for (int I = 0; I)

< 1000; i++) { Counter++; Thread.Sleep(1); } }); t1.Start(); Thread t2 = new Thread(() =>

{for (int I = 0; I)

< 1000; i++) { Counter++; Thread.Sleep(1); } }); t2.Start(); Thread.Sleep(3000); Console.WriteLine(Counter); Console.ReadKey(); } }} 我们猜想一下程序的输出结果是多少?2000?我们运行程序看一下输出结果:

We see that the final output of the program is completely different from what we predicted. What is the reason for this? This is the problem caused by thread synchronization.

Thread synchronization problem: is to solve the problem of multiple threads operating a resource at the same time.

In the above example, both T1 and T2 threads increase the value of the variable Counter by 1. Suppose that the T1 thread reads the Counter value of 200. it is possible that the T2 thread executes very fast. when the T1 thread reads the countermeasure value, the T2 thread has changed the value of Counter to 205. after the T1 thread finishes executing, the value of Counter will be changed to 201. this will lead to the problem of thread synchronization. So how to solve this problem?

Second, solve the problem of thread synchronization 1. Lock

The easiest way to solve the thread synchronization problem is to use lock. Lock can solve the problem caused by multiple threads operating on a resource at the same time. Lock is a keyword in C #, which locks a resource. The characteristic of lock is that only one thread can enter the scope of the lock object at a time, and other lock threads have to wait. Let's look at the optimized code below:

Using System;using System.Threading;namespace ThreadSynchDemo {class Program {private static int Counter = 0; / / define a locker object private static Object locker = new Object (); static void Main (string [] args) {# region has thread synchronization problems / / Thread T1 = new Thread (() = > {/ / for (int I = 0; I)

< 1000; i++) // { // Counter++; // Thread.Sleep(1); // } //}); //t1.Start(); //Thread t2 = new Thread(() =>

{/ / for (int I = 0; I

< 1000; i++) // { // Counter++; // Thread.Sleep(1); // } //}); //t2.Start(); #endregion #region 使用Lock解决线程同步问题 Thread t1 = new Thread(() =>

{for (int I = 0; I)

< 1000; i++) { lock(locker) { Counter++; } Thread.Sleep(1); } }); t1.Start(); Thread t2 = new Thread(() =>

{for (int I = 0; I)

< 1000; i++) { lock (locker) { Counter++; } Thread.Sleep(1); } }); t2.Start(); #endregion Thread.Sleep(3000); Console.WriteLine(Counter); Console.ReadKey(); } }} 这时我们在运行程序,查看输出结果:

At this point, the output is correct.

Note: lock can only lock the same object, if it is a different object, there will be thread synchronization problems. The object locked by lock must be an object of reference type.

We are defining an object of type Object, and lock locks two objects separately to see what the result is:

Using System;using System.Threading;namespace ThreadSynchDemo {class Program {private static int Counter = 0; / define a locker object private static Object locker = new Object (); / / define locker2 private static Object locker2 = new Object () Static void Main (string [] args) {# region has thread synchronization problems / / Thread T1 = new Thread (() = > {/ / for (int I = 0; I)

< 1000; i++) // { // Counter++; // Thread.Sleep(1); // } //}); //t1.Start(); //Thread t2 = new Thread(() =>

{/ / for (int I = 0; I

< 1000; i++) // { // Counter++; // Thread.Sleep(1); // } //}); //t2.Start(); #endregion #region 使用Lock解决线程同步问题 //Thread t1 = new Thread(() =>

{/ / for (int I = 0; I

< 1000; i++) // { // lock(locker) // { // Counter++; // } // Thread.Sleep(1); // } //}); //t1.Start(); //Thread t2 = new Thread(() =>

{/ / for (int I = 0; I

< 1000; i++) // { // lock (locker) // { // Counter++; // } // Thread.Sleep(1); // } //}); //t2.Start(); #endregion #region 使用lock锁住不同的对象也会有线程同步问题 Thread t1 = new Thread(() =>

{for (int I = 0; I)

< 1000; i++) { lock (locker) { Counter++; } Thread.Sleep(1); } }); t1.Start(); Thread t2 = new Thread(() =>

{for (int I = 0; I)

< 1000; i++) { lock (locker2) { Counter++; } Thread.Sleep(1); } }); t2.Start(); #endregion Thread.Sleep(3000); Console.WriteLine(Counter); Console.ReadKey(); } }} 程序运行结果: 可以看到,这时还是会有线程同步的问题。虽然使用了lock,但是我们锁住的是不同的对象,这样也会有线程同步问题。lock必须锁住同一个对象才可以。 我们下面在来看一个多线程同步问题的例子: using System;using System.Threading;namespace ThreadSynchDemo2{ class Program { static int Money = 100; /// /// 定义一个取钱的方法 /// /// static void QuQian(string name) { Console.WriteLine(name + "查看一下余额" + Money); int yue = Money - 1; Console.WriteLine(name + "取钱"); Money = yue; Console.WriteLine(name + "取完了,剩" + Money); } static void Main(string[] args) { Thread t1 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { QuQian("t2"); } }); Thread t2 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { QuQian("t2"); } }); t1.Start(); t2.Start(); t1.Join(); t2.Join(); Console.WriteLine("余额" + Money); Console.ReadKey(); } }} 我们看一下输出结果: 可以看到,最终的余额并不是80,这也是线程同步带来的问题,如何解决。解决思路就是使用同步的技术避免两个线程同时修改一个余额。 2、最大粒度——同步方法 在方法上面使用[MethodImpl(MethodImplOptions.Synchronized)],标记该方法是同步方法,这样一个方法只能同时被一个线程访问。我们在QuQian的方法上面标记,修改后的代码如下: using System;using System.Runtime.CompilerServices;using System.Threading;namespace ThreadSynchDemo2{ class Program { static int Money = 100; /// /// 定义一个取钱的方法,在上面标记为同步方法 /// /// [MethodImpl(MethodImplOptions.Synchronized)] static void QuQian(string name) { Console.WriteLine(name + "查看一下余额" + Money); int yue = Money - 1; Console.WriteLine(name + "取钱"); Money = yue; Console.WriteLine(name + "取完了,剩" + Money); } static void Main(string[] args) { Thread t1 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { QuQian("t2"); } }); Thread t2 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { QuQian("t2"); } }); t1.Start(); t2.Start(); t1.Join(); t2.Join(); Console.WriteLine("余额" + Money); Console.ReadKey(); } }} 程序输出结果: 现在的方法就是"线程安全"的了。什么是"线程安全"呢?"线程安全"是指方法可以被多个线程随意调用,而不会出现混乱。如果出现了混乱,那么就是"线程不安全"的。"线程安全"的方法可以在多线程里面随意的使用。 3、对象互斥锁 对象互斥锁就是我们上面讲的lock。我们在用lock来修改上面QuQian的例子: using System;using System.Runtime.CompilerServices;using System.Threading;namespace ThreadSynchDemo2{ class Program { static int Money = 100; /// /// 定义一个取钱的方法,在上面标记为同步方法 /// /// //[MethodImpl(MethodImplOptions.Synchronized)] //static void QuQian(string name) //{ // Console.WriteLine(name + "查看一下余额" + Money); // int yue = Money - 1; // Console.WriteLine(name + "取钱"); // Money = yue; // Console.WriteLine(name + "取完了,剩" + Money); //} private static object locker = new object(); static void QuQian(string name) { Console.WriteLine(name + "查看一下余额" + Money); int yue = Money - 1; Console.WriteLine(name + "取钱"); Money = yue; Console.WriteLine(name + "取完了,剩" + Money); } static void Main(string[] args) { Thread t1 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { // 使用对象互斥锁 lock(locker) { QuQian("t1"); } } }); Thread t2 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { lock (locker) { QuQian("t2"); } } }); t1.Start(); t2.Start(); t1.Join(); t2.Join(); Console.WriteLine("余额" + Money); Console.ReadKey(); } }} 程序输出结果: 可以看到,最终的输出结果还是80。 同一时刻只能有一个线程进入同一个对象的lock代码块。必须是同一个对象才能起到互斥的作用。lock后必须是引用类型,不一定是object,只要是对象就行。 锁对象选择很重要,选不对就起不到同步的作用;选不对还有可能会造成其他地方被锁,比如用字符串做锁(因为字符串缓冲池导致导致可能用的是其他地方正在使用的锁),所以不建议使用字符串做锁。下面的代码就是不允许的: lock("locker") 两个方法如果都用一个对象做锁,那么访问A的时候就不能访问B,因此锁选择很重要。 4、Monitor 其实lock关键字就是对Monitor的简化调用,lock最终会被编译成Monitor,因此一般不直接使用Monitor类,看下面代码: using System;using System.Threading;namespace MonitorDemo{ class Program { static int Money = 100; private static object locker = new object(); static void QuQian(string name) { // 等待没有人锁定locker对象,就锁定它,然后继续执行 Monitor.Enter(locker); try { Console.WriteLine(name + "查看一下余额" + Money); int yue = Money - 1; Console.WriteLine(name + "取钱"); Money = yue; Console.WriteLine(name + "取完了,剩" + Money); } finally { // 释放locker对象的锁 Monitor.Exit(locker); } } static void Main(string[] args) { Thread t1 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { QuQian("t1"); } }); Thread t2 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { QuQian("t2"); } }); t1.Start(); t2.Start(); t1.Join(); t2.Join(); Console.WriteLine("余额" + Money); Console.ReadKey(); } }} 程序输出结果: Monitor类里面还有TryEnter方法,如果Enter的时候有人在占用锁,它不会等待,而是会返回false。看下面的示例代码: using System;using System.Threading;namespace MonitorDemo{ class Program { static int Money = 100; private static object locker = new object(); static void QuQian(string name) { // 等待没有人锁定locker对象,就锁定它,然后继续执行 Monitor.Enter(locker); try { Console.WriteLine(name + "查看一下余额" + Money); int yue = Money - 1; Console.WriteLine(name + "取钱"); Money = yue; Console.WriteLine(name + "取完了,剩" + Money); } finally { // 释放locker对象的锁 Monitor.Exit(locker); } } static void F1(int i) { if (!Monitor.TryEnter(locker)) { Console.WriteLine("有人在锁着呢"); return; } Console.WriteLine(i); Monitor.Exit(locker); } static void Main(string[] args) { //Thread t1 = new Thread(() =>

{/ / for (int I = 0; I

< 10; i++) // { // QuQian("t1"); // } //}); //Thread t2 = new Thread(() =>

{/ / for (int I = 0; I

< 10; i++) // { // QuQian("t2"); // } //}); Thread t1 = new Thread(() =>

{for (int I = 0; I)

< 10; i++) { F1(i); } }); Thread t2 = new Thread(() =>

{for (int I = 0; I < 10; iTunes +) {F1 (I);}}); t1.Start (); t2.Start (); t1.Join (); t2.Join (); Console.WriteLine ("balance" + Money) Console.ReadKey ();}

The output result of the program:

This is the end of this article on "sample analysis of thread synchronization in C# multithreading". I hope the above content can be helpful to you, so that you can learn more knowledge. if you think the article is good, please share it for more people to see.

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