C#讀寫者線程(用AutoResetEvent實現同步)

轉載自 http://blog.csdn.net/livelylittlefish/article/details/2735440函數

 

本博客(http://blog.csdn.net/livelylittlefish)貼出做者(三二1、小魚)相關研究、學習內容所作的筆記,歡迎廣大朋友指正!學習

 

C#讀寫者線程(用AutoResetEvent實現同步)spa

 

 

1. AutoResetEvent簡介.net

 

通知正在等待的線程已發生事件。沒法繼承此類。線程

 

經常使用方法簡介:code

  • AutoResetEvent(bool initialState):構造函數,用一個指示是否將初始狀態設置爲終止的布爾值初始化該類的新實例。

    false:無信號,子線程的WaitOne方法不會被自動調用     true:有信號,子線程的WaitOne方法會被自動調用對象

  • public bool Reset ():將事件狀態設置爲非終止狀態,致使線程阻止;若是該操做成功,則返回true;不然,返回false。
  • public bool Set ():將事件狀態設置爲終止狀態,容許一個或多個等待線程繼續;若是該操做成功,則返回true;不然,返回false。

    對於具備 EventResetMode.AutoReset(包括 AutoResetEvent)的 EventWaitHandle,Set 方法釋放單個線程。若是沒有等待線程,等待句柄將一直保持終止狀態,直到某個線程嘗試等待它,或者直到它的 Reset 方法被調用。blog

 

    對於具備 EventResetMode.ManualReset(包括 ManualResetEvent)的 EventWaitHandle,調用Set 方法將使等待句柄一直保持終止狀態,直到它的 Reset 方法被調用。繼承

 

  • WaitOne方法

       當在派生類中重寫時,阻止當前線程,直到當前的 WaitHandle 收到信號。事件

  1. WaitHandle.WaitOne () 當在派生類中重寫時,阻止當前線程,直到當前的 WaitHandle 收到信號。 由.NET Compact Framework 支持。
  2. WaitHandle.WaitOne(Int32, Boolean)  在派生類中被重寫時,阻止當前線程,直到當前的WaitHandle 收到信號,使用 32 位有符號整數度量時間間隔並指定是否在等待以前退出同步域。由 .NET Compact Framework 支持。
  3. WaitHandle.WaitOne(TimeSpan, Boolean)  在派生類中被重寫時,阻止當前線程,直到當前實例收到信號,使用 TimeSpan 度量時間間隔並指定是否在等待以前退出同步域。

2. 讀寫者線程例子

 

本例子中,主線程做爲寫線程,要對某個數據(本例中是個變量)賦值(即寫動做),而讀線程則等待寫線程每次寫完數據發出通知,待讀線程收到通知後,將數據讀出並顯示。

[Csharp] view plain copy print ?
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Text; 
  4.  
  5. using System.Threading; 
  6.  
  7. namespace TestAutoResetEvent 
  8.     /// <summary> 
  9.     /// 讀寫者線程 
  10.     /// 主線程寫,子線程讀,且只有將數據寫入後,讀線程才能將其讀出 
  11.     /// </summary> 
  12.     class Program 
  13.     { 
  14.         //寫線程將數據寫入myData 
  15.         staticint myData = 100; 
  16.  
  17.         //讀寫次數 
  18.         constint readWriteCount = 10; 
  19.  
  20.         //false:初始時沒有信號 
  21.         static AutoResetEvent autoResetEvent = new AutoResetEvent(false); 
  22.  
  23.         staticvoid Main(string[] args) 
  24.         { 
  25.             //開啓一個讀線程(子線程) 
  26.             Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); 
  27.             readerThread.Name = "ReaderThread"
  28.             readerThread.Start(); 
  29.  
  30.             for (int i = 1; i <= readWriteCount; i++) 
  31.             { 
  32.                 Console.WriteLine("MainThread writing : {0}", i); 
  33.  
  34.                 //主(寫)線程將數據寫入 
  35.                 myData = i; 
  36.  
  37.                 //主(寫)線程發信號,說明值已寫過了 
  38.                 //即通知正在等待的線程有事件發生 
  39.                 autoResetEvent.Set(); 
  40.  
  41.                 Thread.Sleep(0); 
  42.             } 
  43.  
  44.             //終止線程 
  45.             readerThread.Abort(); 
  46.         } 
  47.  
  48.         staticvoid ReadThreadProc() 
  49.         { 
  50.             while (true
  51.             { 
  52.                 //在數據被寫入前,讀線程等待(其實是等待寫線程發出數據寫完的信號) 
  53.                 autoResetEvent.WaitOne(); 
  54.                 Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); 
  55.             } 
  56.         } 
  57.     } 
  58. }<pre></pre> 
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值,觀察運行結果。

[Csharp] view plain copy print ?
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Text; 
  4.  
  5. using System.Threading; 
  6.  
  7. namespace TestAutoResetEvent 
  8.     /// <summary> 
  9.     /// 讀寫者線程 
  10.     /// 主線程寫,子線程讀,且只有將數據寫入後,讀線程才能將其讀出 
  11.     /// </summary> 
  12.     class Program 
  13.     { 
  14.         //寫線程將數據寫入myData 
  15.         staticint myData = 100; 
  16.  
  17.         //讀寫次數 
  18.         constint readWriteCount = 10; 
  19.  
  20.         //false:初始時沒有信號 
  21.         static AutoResetEvent autoResetEvent = new AutoResetEvent(false); 
  22.  
  23.         staticvoid Main(string[] args) 
  24.         { 
  25.             //開啓一個讀線程(子線程) 
  26.             Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); 
  27.             readerThread.Name = "ReaderThread"
  28.             readerThread.Start(); 
  29.  
  30.             for (int i = 1; i <= readWriteCount; i++) 
  31.             { 
  32.                 Console.WriteLine("MainThread writing : {0}", i); 
  33.  
  34.                 //主(寫)線程將數據寫入 
  35.                 myData = i; 
  36.  
  37.                 //主(寫)線程發信號,說明值已寫過了 
  38.                 //即通知正在等待的線程有事件發生 
  39.                 autoResetEvent.Set(); 
  40.  
  41.                 Thread.Sleep(1); 
  42.             } 
  43.  
  44.             //終止線程 
  45.             readerThread.Abort(); 
  46.         } 
  47.  
  48.         staticvoid ReadThreadProc() 
  49.         { 
  50.             while (true
  51.             { 
  52.                 //在數據被寫入前,讀線程等待(其實是等待寫線程發出數據寫完的信號) 
  53.                 autoResetEvent.WaitOne(); 
  54.                 Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); 
  55.             } 
  56.         } 
  57.     } 
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再進行修改

主線程在寫完數據後根本不睡嗎呢?這個時候會發生什麼事情?

[Csharp] view plain copy print ?
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Text; 
  4.  
  5. using System.Threading; 
  6.  
  7. namespace TestAutoResetEvent 
  8.     /// <summary> 
  9.     /// 讀寫者線程 
  10.     /// 主線程寫,子線程讀,且只有將數據寫入後,讀線程才能將其讀出 
  11.     /// </summary> 
  12.     class Program 
  13.     { 
  14.         //寫線程將數據寫入myData 
  15.         staticint myData = 100; 
  16.  
  17.         //讀寫次數 
  18.         constint readWriteCount = 10; 
  19.  
  20.         //false:初始時沒有信號 
  21.         static AutoResetEvent autoResetEvent = new AutoResetEvent(false); 
  22.  
  23.         staticvoid Main(string[] args) 
  24.         { 
  25.             //開啓一個讀線程(子線程) 
  26.             Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); 
  27.             readerThread.Name = "ReaderThread"
  28.             readerThread.Start(); 
  29.  
  30.             for (int i = 1; i <= readWriteCount; i++) 
  31.             { 
  32.                 Console.WriteLine("MainThread writing : {0}", i); 
  33.  
  34.                 //主(寫)線程將數據寫入 
  35.                 myData = i; 
  36.  
  37.                 //主(寫)線程發信號,說明值已寫過了 
  38.                 //即通知正在等待的線程有事件發生 
  39.                 autoResetEvent.Set(); 
  40.  
  41.                 //Thread.Sleep(1); 
  42.             } 
  43.  
  44.             //終止線程 
  45.             readerThread.Abort(); 
  46.         } 
  47.  
  48.         staticvoid ReadThreadProc() 
  49.         { 
  50.             while (true
  51.             { 
  52.                 //在數據被寫入前,讀線程等待(其實是等待寫線程發出數據寫完的信號) 
  53.                 autoResetEvent.WaitOne(); 
  54.                 Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); 
  55.             } 
  56.         } 
  57.     } 
  58. }<pre></pre> 
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,觀察運行結果。

 

[Csharp] view plain copy print ?
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Text; 
  4.  
  5. using System.Threading; 
  6.  
  7. namespace TestAutoResetEvent 
  8.     /// <summary> 
  9.     /// 讀寫者線程 
  10.     /// 主線程寫,子線程讀,且只有將數據寫入後,讀線程才能將其讀出 
  11.     /// </summary> 
  12.     class Program 
  13.     { 
  14.         //寫線程將數據寫入myData 
  15.         staticint myData = 100; 
  16.  
  17.         //讀寫次數 
  18.         constint readWriteCount = 10; 
  19.  
  20.         //false:初始時沒有信號 
  21.         static AutoResetEvent autoResetEvent = new AutoResetEvent(true); 
  22.  
  23.         staticvoid Main(string[] args) 
  24.         { 
  25.             //開啓一個讀線程(子線程) 
  26.             Thread readerThread = new Thread(new ThreadStart(ReadThreadProc)); 
  27.             readerThread.Name = "ReaderThread"
  28.             readerThread.Start(); 
  29.  
  30.             for (int i = 1; i <= readWriteCount; i++) 
  31.             { 
  32.                 Console.WriteLine("MainThread writing : {0}", i); 
  33.  
  34.                 //主(寫)線程將數據寫入 
  35.                 myData = i; 
  36.  
  37.                 //主(寫)線程發信號,說明值已寫過了 
  38.                 //即通知正在等待的線程有事件發生 
  39.                 autoResetEvent.Set(); 
  40.  
  41.                 Thread.Sleep(0); 
  42.             } 
  43.  
  44.             //終止線程 
  45.             readerThread.Abort(); 
  46.         } 
  47.  
  48.         staticvoid ReadThreadProc() 
  49.         { 
  50.             while (true
  51.             { 
  52.                 //在數據被寫入前,讀線程等待(其實是等待寫線程發出數據寫完的信號) 
  53.                 autoResetEvent.WaitOne(); 
  54.                 Console.WriteLine("{0} reading : {1}", Thread.CurrentThread.Name, myData); 
  55.             } 
  56.         } 
  57.     } 
  58. }<pre></pre> 
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方法會被自動調用。

相關文章
相關標籤/搜索