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」方法釋放資源以後才能訪問數據庫。

相關文章
相關標籤/搜索