轉載自 http://blog.csdn.net/livelylittlefish/article/details/2735440函數
本博客(http://blog.csdn.net/livelylittlefish)貼出做者(三二1、小魚)相關研究、學習內容所作的筆記,歡迎廣大朋友指正!學習
C#讀寫者線程(用AutoResetEvent實現同步)spa
1. AutoResetEvent簡介.net
通知正在等待的線程已發生事件。沒法繼承此類。線程
經常使用方法簡介:code
false:無信號,子線程的WaitOne方法不會被自動調用 true:有信號,子線程的WaitOne方法會被自動調用對象
對於具備 EventResetMode.AutoReset(包括 AutoResetEvent)的 EventWaitHandle,Set 方法釋放單個線程。若是沒有等待線程,等待句柄將一直保持終止狀態,直到某個線程嘗試等待它,或者直到它的 Reset 方法被調用。blog
對於具備 EventResetMode.ManualReset(包括 ManualResetEvent)的 EventWaitHandle,調用Set 方法將使等待句柄一直保持終止狀態,直到它的 Reset 方法被調用。繼承
當在派生類中重寫時,阻止當前線程,直到當前的 WaitHandle 收到信號。事件
2. 讀寫者線程例子
本例子中,主線程做爲寫線程,要對某個數據(本例中是個變量)賦值(即寫動做),而讀線程則等待寫線程每次寫完數據發出通知,待讀線程收到通知後,將數據讀出並顯示。
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace TestAutoResetEvent { /// /// 讀寫者線程 /// 主線程寫,子線程讀,且只有將數據寫入後,讀線程才能將其讀出 /// class Program { //寫線程將數據寫入myData static int myData = 100; //讀寫次數 const int readWriteCount = 10; //false:初始時沒有信號 static AutoResetEvent autoResetEvent = new AutoResetEvent(false); static void Main(string[] args) { //開啓一個讀線程(子線程) Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); readerThread.Name = "ReaderThread"; readerThread.Start(); for (int i = 1; i <= readWriteCount; i++) { Console.WriteLine("MainThread writing : {0}", i); //主(寫)線程將數據寫入 myData = i; //主(寫)線程發信號,說明值已寫過了 //即通知正在等待的線程有事件發生 autoResetEvent.Set(); Thread.Sleep(0); } //終止線程 readerThread.Abort(); } static void ReadThreadProc() { while (true) { //在數據被寫入前,讀線程等待(其實是等待寫線程發出數據寫完的信號) autoResetEvent.WaitOne(); Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); } } } }
運行結果以下:
由運行結果能夠看出,寫線程寫入的數據有丟失,主要緣由是寫線程沒有給讀線程留足夠的時間去進行讀操做。
3. 對1進行修改
將主線程睡眠時間改成非0值,觀察運行結果。
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace TestAutoResetEvent { /// /// 讀寫者線程 /// 主線程寫,子線程讀,且只有將數據寫入後,讀線程才能將其讀出 /// class Program { //寫線程將數據寫入myData static int myData = 100; //讀寫次數 const int readWriteCount = 10; //false:初始時沒有信號 static AutoResetEvent autoResetEvent = new AutoResetEvent(false); static void Main(string[] args) { //開啓一個讀線程(子線程) Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); readerThread.Name = "ReaderThread"; readerThread.Start(); for (int i = 1; i <= readWriteCount; i++) { Console.WriteLine("MainThread writing : {0}", i); //主(寫)線程將數據寫入 myData = i; //主(寫)線程發信號,說明值已寫過了 //即通知正在等待的線程有事件發生 autoResetEvent.Set(); Thread.Sleep(1); } //終止線程 readerThread.Abort(); } static void ReadThreadProc() { while (true) { //在數據被寫入前,讀線程等待(其實是等待寫線程發出數據寫完的信號) autoResetEvent.WaitOne(); Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); } } } }
運行結果以下:
有結果可知,當主線程睡眠時間大於0值時,讀線程即有足夠的時間讀取寫線程寫入的數據。這個睡眠時間的長短能夠根據實際應用中子線程的計算量設定。
4. 對1再進行修改
主線程在寫完數據後根本不睡嗎呢?這個時候會發生什麼事情?
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace TestAutoResetEvent { /// /// 讀寫者線程 /// 主線程寫,子線程讀,且只有將數據寫入後,讀線程才能將其讀出 /// class Program { //寫線程將數據寫入myData static int myData = 100; //讀寫次數 const int readWriteCount = 10; //false:初始時沒有信號 static AutoResetEvent autoResetEvent = new AutoResetEvent(false); static void Main(string[] args) { //開啓一個讀線程(子線程) Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); readerThread.Name = "ReaderThread"; readerThread.Start(); for (int i = 1; i <= readWriteCount; i++) { Console.WriteLine("MainThread writing : {0}", i); //主(寫)線程將數據寫入 myData = i; //主(寫)線程發信號,說明值已寫過了 //即通知正在等待的線程有事件發生 autoResetEvent.Set(); //Thread.Sleep(1); } //終止線程 readerThread.Abort(); } static void ReadThreadProc() { while (true) { //在數據被寫入前,讀線程等待(其實是等待寫線程發出數據寫完的信號) autoResetEvent.WaitOne(); Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); } } } }
運行結果以下:
有結果可知,不睡眠的狀況和睡眠時間爲0(即Thread.Sleep(0);)效果產很少,只是不睡眠丟失的數據更多了。
5. 對1再修改
將傳遞給AutoResetEvent的構造函數的參數設置爲true,觀察運行結果。
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace TestAutoResetEvent { /// /// 讀寫者線程 /// 主線程寫,子線程讀,且只有將數據寫入後,讀線程才能將其讀出 /// class Program { //寫線程將數據寫入myData static int myData = 100; //讀寫次數 const int readWriteCount = 10; //false:初始時沒有信號 static AutoResetEvent autoResetEvent = new AutoResetEvent(true); static void Main(string[] args) { //開啓一個讀線程(子線程) Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); readerThread.Name = "ReaderThread"; readerThread.Start(); for (int i = 1; i <= readWriteCount; i++) { Console.WriteLine("MainThread writing : {0}", i); //主(寫)線程將數據寫入 myData = i; //主(寫)線程發信號,說明值已寫過了 //即通知正在等待的線程有事件發生 autoResetEvent.Set(); Thread.Sleep(0); } //終止線程 readerThread.Abort(); } static void ReadThreadProc() { while (true) { //在數據被寫入前,讀線程等待(其實是等待寫線程發出數據寫完的信號) autoResetEvent.WaitOne(); Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); } } } }
運行結果以下:
若將主線程的睡眠時間改成任意非0值,其運行結果均爲下圖所示的結果。
6. 其餘修改
將主線程調用AutoResetEvent對象的Set方法刪除,分別對AutoResetEvent的構造函數的參數爲false和true觀察運行結果。
爲false,運行結果以下圖所示。
爲true,運行結果以下圖所示。
至此,我想咱們應該明白AutoResetEvent構造函數的參數的意義了。 false:無信號,子線程的WaitOne方法不會被自動調用; true:有信號,子線程的WaitOne方法會被自動調用。