国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

.NET組件程序設計之線程、并發管理(二)

2019-11-17 03:08:16
字體:
來源:轉載
供稿:網友

.NET組件程序設計之線程、并發管理(二)

.Net組件程序設計之線程、并發管理(二)

2.同步線程

  • 手動同步

    • 監視器

    • 互斥

    • 可等待事件

同步線程

所有的.NET組件都支持在多線程的環境中運行,可以被多個線程并發訪問,如果沒有線程同步,這樣的后果是當多個線程同時訪問 對象狀態時,對象的狀態可能被破壞,造成不一致性。.NET提供了兩種方法來避免這樣的問題,使得我們設計的組件更加健壯。 第一種是自動同步,讓你使用一個屬性來修飾組件,這樣就可以把組件交給.NET了,同步的事情也就交給了.NET。 第二種是手動同步,這是讓你使用.NET提供的同步對象來實現線程同步,也不是太復雜,本篇將會對手動同步來稍作講解。

2.1 手動同步

.NET手動同步提供了一套豐富的同步鎖,上一節說到同步域,同步域事實上是一個巨大的宏鎖,而手動同步則提供了 對被鎖對象的細粒度控制,可以控制訪問對象、單一成員甚至是單行的代碼。這樣的好處就是有可能的提高系統的性能和吞吐量。

2.1.1 監視器

監視器是一種只能和引用類型一塊工作的鎖。

2.1.1-1

 1     public class ManualSynchronization 2     { 3         public void DoSomeThing() 4         { 5             for (int i = 0; i < 100; i++) 6             { 7                 Console.WriteLine(i.ToString()); 8             } 9         }10     }
 1 ManualSynchronization monitorcase = new ManualSynchronization(); 2  3 Monitor.Enter(monitorcase); 4 try 5 { 6     monitorcase.DoSomeThing(); 7 } 8 finally 9 {10     Monitor.Exit(monitorcase);11 }

任何線程的任何對象都可以調用Enter()方法來鎖定對象,如果Monitor正在被一個線程使用,而這個時候又有一個線程來請求對象Enter(),這樣就會使第二個線程阻塞,直到第一個線程調用Exit(),如果這時有多個線程請求對象Enter(),它們就會被放置在一個叫做鎖隊列的隊列里,并依照隊列的順序獲得服務順序。

你還可以使用Monitor類為靜態類方法或靜態屬性提供安全線程訪問,方法是讓Monitor鎖定該類型,而不是一個實例:

2.1.1-2

 1     public class ManualSynchronization 2     { 3         public static void SDoSomeThing() 4         { 5             for (int i = 0; i < 100; i++) 6             { 7                 Console.WriteLine(i.ToString()); 8             } 9         }10     }
1            Monitor.Enter(typeof(ManualSynchronization));2            try3            {4                ManualSynchronization.SDoSomeThing();5            }6            finally7            {8                Monitor.Exit(typeof(ManualSynchronization));9            }

在C#中為了簡化這樣的寫法,提供了lock語句,使編譯器在try/finally語句中自動產生對Enter()和Exit()的調用。

比如你寫下這樣的代碼等同于2.1.1-1的示例代碼:

2.1.1-3

1 ManualSynchronization monitorcase = new ManualSynchronization();2 lock(monitorcase)3 {4     monitorcase.DoSomeThing();5 } 

像上面的代碼這樣寫看似沒什么問題了,因為這個lock所定對象實例或者是對象類型,是根據客戶端開發者的判斷而定的,這樣的鎖定方式與客戶端耦合度大,看下以下代碼:

2.1.1-4

 1     public class ManualSynchronization 2     { 3         public void DoSomeThing() 4         { 5             lock (this) 6             { 7                 for (int i = 0; i < 100; i++) 8                 { 9                     Console.WriteLine(i.ToString());10                 }11             }12         }13     }
1 ManualSynchronization monitorcase = new ManualSynchronization();2 monitorcase.DoSomeThing();

這樣感覺是不是舒服不少,這就是方法同步了,.NET內部也對它提供了支持,定義在System.Runtime.CompilerServices命名空間里的MethodImpl方法屬性接受一個MethodImplOptions類型的枚舉。其中一個枚舉值是MethodImplOptions.Synchronized。當運行這個枚舉值的時候,編輯器就指示.NET運行時在方法入口鎖定對象,語義和2.1.1-4的代碼斷相同:

2.1.1-5

1     public class ManualSynchronization2     {3         [MethodImpl( MethodImplOptions.Synchronized)]4         public void DoSomeThingSynchroniezd()5         {6             Console.WriteLine("studycase");7         }8     } 

2.1.2 互斥

這一個小節要講到的是Mutex類,它是從WaitHandle派生的類,它保證了各個線程在某個資源或代碼塊上相互排斥。

2.1.2-1

 1     public class MutexDom:IDisposable 2     { 3         public MutexDom(){} 4         PRivate int _Num = 0; 5         public int Num 6         { 7             get 8             { 9                 return _Num;10             }11             set12             {13                 _Num = value;14             }15         }16         public void Dom()17         {18                  for (int i = 0; i < 100; i++)19                 {20                     Num = Num + i;21                     Console.WriteLine(Thread.CurrentThread.Name + "_" + Num.ToString() +"_"+Thread.CurrentThread.ManagedThreadId.ToString());22                 }23 24             25         }26         public void Dispose()27         {28          29         }30 31         public static void Test()32         {33             MutexDom mutexDom=new MutexDom();34             ThreadStart threadStart=new ThreadStart(mutexDom.Dom);35             Thread thread1 = new Thread(threadStart);36             thread1.Name = "Thread_One";37             Thread thread2 = new Thread(threadStart);38             thread2.Name = "Thread_Two";39             thread1.Start();40             thread2.Start();41         }42     }

MutexDom.Test();啟動測試,我所希望的效果是Dom()方法是有序的執行的,而我用了一個int類型的Nun屬性來作為計數器,那我們就一起來看一下結果吧(可能每次運行結果不一樣)

我所期望的在線程Thread_One中執行0遞增至99的值時4950,而在結果中已經超出了這個范圍,這說明了什么?說明了兩個線程在交替的對Num進行操作。修改一下代碼,再來看一下:

2.1.2-2

 1     public class MutexDom:IDisposable 2     { 3         private Mutex _Mutex; 4         public MutexDom() 5         { 6             _Mutex = new Mutex(); 7         } 8         private int _Num = 0; 9         public int Num10         {11             get12             {13                 return _Num;14             }15             set16             {17                 _Num = value;18             }19         }20         public void Dom()21         {22             _Mutex.WaitOne();//如果當前資源被占用 則等待占用它的線程發送消息23             try24             {25                 for (int i = 0; i < 100; i++)26                 {27                     Num = Num + i;28                     Console.WriteLine(Thread.CurrentThread.Name + "_" + Num.ToString() +"_"+Thread.CurrentThread.ManagedThreadId.ToString());29                 }30             }31             finally32             {33                 _Mutex.ReleaseMutex();34             }35             36         }37         public void Dispose()38         {39             _Mutex.Close();40         }41 42         public static void Test()43         {44             MutexDom mutexDom=new MutexDom();45             ThreadStart threadStart=new ThreadStart(mutexDom.Dom);46             Thread thread1 = new Thread(threadStart);47             thread1.Name = "Thread_One";48             Thread thread2 = new Thread(threadStart);49             thread2.Name = "Thread_Two";50             51             thread1.Start();52             thread2.Start();53             54         }55     }

從結果中得出,是線程Thread_Two先執行的,這個沒關系,只要看它的結果值就行了,這就說明了,在線程"Thread_Two"執行對Dom()方法操作的時候"Thread_One"是肯定已經啟動了的,而且是在等待"Thread_Two"的釋放消息,這樣就保持了對象狀態的一致性,這個時候"Thread_One"是在一個等待隊列中的。如果這個時候"Thread_One"調用ReleaseMutex()方法,是會報錯的,因為ReleaseMutex()方法是只能當前所占有的線程來進行釋放,互斥就這樣完成了。

2.1.3 可等待事件

EventWaitHandle類派生于WaitHandle,被用于跨線程通知事件。 它有兩種狀態:信號已發狀態、信號未發狀態。 Set()方法和 Reset()方法分別把句柄狀態設置為信號已發或信號未發。 它有兩種使用方式,一種是手動重置,還有一種是自動重置。是通過給構造函數提供一個EventResetMode類型的枚舉值,

1     public enum EventResetMode2     {3        AutoReset,4        ManualReset5     }

.NET提供了EventWaitHandle的兩個強類型子類,定義如下:

 1     public class ManualResetEvent:EventWaitHandle 2     { 3         public ManualResetEvent(bool initialState):base(initialState,EventResetMode.ManualReset) 4         {} 5     } 6     public sealed class AutoResetEvent : EventWaitHandle 7     { 8         public AutoResetEvent(bool initialState):base(initialState,EventResetMode.AutoReset) 9         {}10     }

先來看一下手動重置:

2.1.3-1

 1     public class EventDom:IDisposable 2     { 3         ManualResetEvent _WaitHandle; 4         public EventDom() 5         { 6             _WaitHandle = new ManualResetEvent(true); 7  8             Thread thread = new Thread(DoWork); 9             thread.Start();10         }11         private void DoWork()12         {13             int num = 0;14             while (true)15             {16                 _WaitHandle.WaitOne();17                 num++;18                 Console.WriteLine("EventDom_" + num.ToString());19             }20         }21         public void StartThread()22         {23             _WaitHandle.Set();24
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 浦城县| 马尔康县| 兰溪市| 柳州市| 额敏县| 且末县| 宝鸡市| 墨江| 满洲里市| 揭西县| 灵丘县| 英超| 扶沟县| 大同市| 丰镇市| 微山县| 宜宾县| 广元市| 永川市| 增城市| 合山市| 龙海市| 襄樊市| 大庆市| 清水河县| 延川县| 井冈山市| 蛟河市| 吉首市| 赤峰市| 梧州市| 开江县| 桂平市| 黔西| 集贤县| 平湖市| 静海县| 庆城县| 枣阳市| 静宁县| 缙云县|