C#多线程之线程同步篇1

  在多线程(线程同步)中,咱们将学习多线程中操做共享资源的技术,学习到的知识点以下所示:数据库

  • 执行基本的原子操做
  • 使用Mutex构造
  • 使用SemaphoreSlim构造
  • 使用AutoResetEvent构造
  • 使用ManualResetEventSlim构造
  • 使用CountdownEvent构造
  • 使用Barrier构造
  • 使用ReaderWriterLockSlim构造
  • 使用SpinWait构造

 1、执行基本的原子操做安全

  在这一小节中,咱们将学习如何在没有阻塞线程(blocking threads)发生的状况下,在一个对象上执行基本的原子操做并能阻止竞争条件(race condition)的发生。操做步骤以下所示:多线程

一、使用Visual Studio 2015建立一个新的控制台应用程序。ide

二、双击打开“Program.cs”文件,编写代码以下所示:学习

 1 using System;
 2 using System.Threading;
 3 using static System.Console;
 4 
 5 namespace Recipe01
 6 {
 7     abstract class CounterBase
 8     {
 9         public abstract void Increment();
10 
11         public abstract void Decrement();
12     }
13 
14     class Counter : CounterBase
15     {
16         private int count;
17 
18         public int Count => count;
19 
20         public override void Increment()
21         {
22             count++;
23         }
24 
25         public override void Decrement()
26         {
27             count--;
28         }
29     }
30 
31     class CounterNoLock : CounterBase
32     {
33         private int count;
34 
35         public int Count => count;
36 
37         public override void Increment()
38         {
39             Interlocked.Increment(ref count); 40         }
41 
42         public override void Decrement()
43         {
44             Interlocked.Decrement(ref count); 45         }
46     }
47 
48     class Program
49     {
50         static void TestCounter(CounterBase c)
51         {
52             for (int i = 0; i < 100000; i++)
53             {
54                 c.Increment();
55                 c.Decrement();
56             }
57         }
58 
59         static void Main(string[] args)
60         {
61             WriteLine("Incorrect counter");
62 
63             var c1 = new Counter();
64 
65             var t1 = new Thread(() => TestCounter(c1));
66             var t2 = new Thread(() => TestCounter(c1));
67             var t3 = new Thread(() => TestCounter(c1));
68             t1.Start();
69             t2.Start();
70             t3.Start();
71             t1.Join();
72             t2.Join();
73             t3.Join();
74 
75             WriteLine($"Total count: {c1.Count}");
76             WriteLine("--------------------------");
77 
78             WriteLine("Correct counter");
79 
80             var c2 = new CounterNoLock();
81 
82             t1 = new Thread(() => TestCounter(c2));
83             t2 = new Thread(() => TestCounter(c2));
84             t3 = new Thread(() => TestCounter(c2));
85             t1.Start();
86             t2.Start();
87             t3.Start();
88             t1.Join();
89             t2.Join();
90             t3.Join();
91 
92             WriteLine($"Total count: {c2.Count}");
93         }
94     }
95 }

三、运行该控制台应用程序,运行效果(每次运行效果可能不一样)以下图所示:spa

  在第63行代码处,咱们建立了一个非线程安全的Counter类的一个对象c1,因为它是非线程安全的,所以会发生竞争条件(race condition)。线程

  在第65~67行代码处,咱们建立了三个线程来运行c1对象的“TestCounter”方法,在该方法中,咱们按顺序对c1对象的count变量执行自增和自减操做。因为c1不是线程安全的,所以在这种状况下,咱们获得的counter值是不肯定的,咱们能够获得0值,但多运行几回,多数状况下会获得不是0值得错误结果。code

  在多线程(基础篇)中,咱们使用lock关键字锁定对象来解决这个问题,可是使用lock关键字会形成其余线程的阻塞。可是,在本示例中咱们没有使用lock关键字,而是使用了Interlocked构造,它对于基本的数学操做提供了自增(Increment)、自减(Decrement)以及其余一些方法。对象

2、使用Mutex构造blog

   在这一小节中,咱们将学习如何使用Mutex构造同步两个单独的程序,即进程间的同步。具体步骤以下所示:

一、使用Visual Studio 2015建立一个新的控制台应用程序。

二、双击打开“Program.cs”文件,编写代码以下所示:

 1 using System;
 2 using System.Threading;
 3 using static System.Console;
 4 
 5 namespace Recipe02
 6 {
 7     class Program
 8     {
 9         static void Main(string[] args)
10         {
11             const string MutexName = "Multithreading";
12 
13             using (var m = new Mutex(false, MutexName))
14             {
15                 // WaitOne方法的做用是阻止当前线程,直到收到其余实例释放的处理信号。
16                 // 第一个参数是等待超时时间,第二个是否退出上下文同步域。
17                 if (!m.WaitOne(TimeSpan.FromSeconds(10), false))
18                 {
19                     WriteLine("Second instance is running!");
20                     ReadLine();
21                 }
22                 else
23                 {
24                     WriteLine("Running!");
25                     ReadLine();
26                     // 释放互斥资源
27                     m.ReleaseMutex();
28                 }
29             }
30 
31             ReadLine();
32         }
33     }
34 }

三、编译代码,执行两次该程序,运行效果以下所示:

第一种状况的运行结果:

第二种状况的运行结果:

  在第11行代码处,咱们定义了一个mutex(互斥量)的名称为“Multithreading”,并在第13行代码处将其传递给了Mutex类的构造方法,该构造方法的第一个参数initialOwner咱们赋值为false,这容许程序得到一个已经被建立的mutex。若是没有任何线程锁定互斥资源,程序只简单地显示“Running”,而后等待按下任何键以释放互斥资源。

  若是咱们启动该程序的第二个实例,若是在10秒内咱们没有在第一个实例下按下任何按钮以释放互斥资源,那么在第二个实例中就会显示“Second instance is running!”,如第一种状况的运行结果所示。若是在10内咱们在第一个实例中按下任何键以释放互斥资源,那么在第二个实例中就会显示“Running”,如第二种状况的运行结果所示。

3、使用SemaphoreSlim构造

  在这一小节中,咱们将学习如何在SemaphoreSlim构造的帮助下,限制同时访问资源的线程数量。具体步骤以下所示:

一、使用Visual Studio 2015建立一个新的控制台应用程序。

二、双击打开“Program.cs”文件,编写代码以下所示:

 1 using System;
 2 using System.Threading;
 3 using static System.Console;
 4 using static System.Threading.Thread;
 5 
 6 namespace Recipe03
 7 {
 8     class Program
 9     {
10         static SemaphoreSlim semaphore = new SemaphoreSlim(4);
11 
12         static void AccessDatabase(string name, int seconds)
13         {
14             WriteLine($"{name} waits to access a database");
15             semaphore.Wait();
16             WriteLine($"{name} was granted an access to a database");
17             Sleep(TimeSpan.FromSeconds(seconds));
18             WriteLine($"{name} is completed");
19             semaphore.Release();
20         }
21 
22         static void Main(string[] args)
23         {
24             for(int i = 1; i <= 6; i++)
25             {
26                 string threadName = "Thread" + i;
27                 int secondsToWait = 2 + 2 * i;
28                 var t = new Thread(() => AccessDatabase(threadName, secondsToWait));
29                 t.Start();
30             }
31         }
32     }
33 }

三、运行该控制台应用程序,运行效果(每次运行效果可能不一样)以下图所示:

 

  在第10行代码处,咱们建立了一个SemaphoreSlim的实例,并对该构造方法传递了参数4,该参数指定了能够有多少个线程同时访问资源。而后,咱们启动了6个不一样名字的线程。每一个线程都试着获取对数据库的访问,可是,咱们限制了最多只有4个线程能够访问数据库,所以,当4个线程访问数据库后,其余2个线程必须等待,直到其余线程完成其工做后,调用“Release”方法释放资源以后才能访问数据库。

相关文章
相关标签/搜索