<form id="j9b99"><th id="j9b99"></th></form>

    南京軟件定制開發

    南京傾心軟件歡迎您訪問本站

    13605185909

    新聞資訊

    NEWS CENTER
    欄目導航

    南京軟件開發之AutoResetEvent使用介紹

    發布時間:Mar 23, 2021         已有 人瀏覽

    之前在博客園看到有位仁兄發表一篇關于AutoResetEvent介紹,看了下他寫的代碼,看上去沒什么問題,但仔細看還是能發現問題。下圖是這位仁兄代碼截圖。

    仁兄博客地址:http://www.cnblogs.com/lzjsky/archive/2011/07/11/2102794.html

    按照這種寫法自己試了下,運行起來并不是他這種結果(運行結果很隨機)。

    原因有以下兩點:

    1、支付線程與取書線程都屬于同級線程,運行先后順序是隨機的

    2、在循環內部調用AutoResetEvent.Set(),不能確定子線程是否按順序執行,有可能主線程已經循環多次,而子線程可能才循環一次

    修正

    首先,要明白實驗的場景。還是引用這位仁兄的例子:“我去書店買書,當我選中一本書后我會去收費處付錢,付好錢后再去倉庫取書。這個順序不能顛倒,我作為主線程,收費處和倉庫做兩個輔助線程” 。

    要實現上圖這種效果,得先確定好執行先后順序(上面已經說過):挑書-->收費-->取書-->完成。

    代碼編寫如下:

    復制代碼
     1 class Program
     2     {
     3         static int _num = 0;
     4         //本例重點對象
     5         static AutoResetEvent _autoReset = new AutoResetEvent(false);
     6 
     7         static AutoResetEvent _autoReset0 = new AutoResetEvent(false);
     8         static AutoResetEvent _autoReset1 = new AutoResetEvent(false);
     9 
    10         //static AutoResetEvent autoReset2 = new AutoResetEvent(false);
    11         //static AutoResetEvent autoReset3 = new AutoResetEvent(false);
    12 
    13         //static object _payMoneyObj = new object();
    14         //static object _getBookObj = new object();
    15 
    16         private static void ThreadPayMoneyProc()
    17         {
    18             while (true)
    19             {
    20                 //_autoReset.WaitOne();
    21                 _autoReset0.WaitOne();
    22                 //lock (_payMoneyObj)
    23                 {
    24                     Console.WriteLine(Thread.CurrentThread.Name + ",編號: " + _num);
    25                     //通知主線程,錢已付完
    26                     //_autoReset2.Set();
    27                 }
    28             }
    29         }
    30 
    31         private static void TreadGetBookProc()
    32         {
    33             while (true)
    34             {
    35                 //_autoReset.WaitOne();
    36                 _autoReset1.WaitOne();
    37                 //lock (_getBookObj)
    38                 {
    39                     Console.WriteLine(Thread.CurrentThread.Name + ",編號: " + _num);
    40                     //通知主線程,書已取走
    41                     //_autoReset3.Set();
    42                 }
    43             }
    44         }
    45 
    46 
    47         static void Main(string[] args)
    48         {
    49             //本案例是通過AutoResetEvent來實現多線程同步
    50             //購買書數量
    51             const int num = 50;
    52 
    53             //付錢線程
    54             Thread threadPayMoney = new Thread(new ThreadStart(ThreadPayMoneyProc));
    55             threadPayMoney.Name = "付錢線程";
    56             //取書線程
    57             Thread threadGetBook = new Thread(new ThreadStart(TreadGetBookProc));
    58             threadGetBook.Name = "取書線程";
    59 
    60             //開始執行線程
    61             threadPayMoney.Start();
    62             threadGetBook.Start();
    63 
    64             //主線程開始選書
    65             Console.WriteLine("----------------主線程開始選書!------------------");
    66             for (int i = 1; i <= num; i++)
    67             {
    68                 Console.WriteLine("主線程選書編號:" + i);
    69                 _num = i;
    70                 //_autoReset.Set();
    71 
    72                 //通知付錢線程
    73                 _autoReset0.Set();
    74                 //主線延時1ms執行(但不知道付錢線程這個過程需要多少時間)
    75                 Thread.Sleep(1);
    76                 //_autoReset2.WaitOne();
    77 
    78                 //付完錢后,通知取書線程
    79                 _autoReset1.Set();
    80                 //主線延時1ms執行(但不知道取書線程這個過程需要多少時間)
    81                 Thread.Sleep(1);
    82                 //_autoReset3.WaitOne();
    83                 Console.WriteLine("-----------------------------------");
    84             }
    85 
    86             Console.ReadKey();
    87 
    88 
    89         }
    90     }
    復制代碼

    運行結果如下圖:

    這樣做,效果是出來了,但主線程不知道付費線程、取書線程執行需要多長時間。上例中給定的是1ms,但如果其中某個子線程超過了給定的休眠時間,主線會繼續往下執行,不會等待子線程處理完成。這樣就導致了買書編號與付錢和取書的編號不同步。也就混亂了。

    這時可以使用AutoResetEvent這個對象。上例中已經使用這個對象。沒錯,還可以在繼續使用。

    代碼如下圖:

    復制代碼
     1 class Program
     2     {
     3         static int _num = 0;
     4         //本例重點對象
     5         static AutoResetEvent _autoReset = new AutoResetEvent(false);
     6 
     7         static AutoResetEvent _autoReset0 = new AutoResetEvent(false);
     8         static AutoResetEvent _autoReset1 = new AutoResetEvent(false);
     9 
    10         static AutoResetEvent _autoReset2 = new AutoResetEvent(false);
    11         static AutoResetEvent _autoReset3 = new AutoResetEvent(false);
    12 
    13         //static object _payMoneyObj = new object();
    14         //static object _getBookObj = new object();
    15 
    16         private static void ThreadPayMoneyProc()
    17         {
    18             while (true)
    19             {
    20                 //_autoReset.WaitOne();
    21                 _autoReset0.WaitOne();
    22                 //lock (_payMoneyObj)
    23                 {
    24                     Console.WriteLine(Thread.CurrentThread.Name + ",編號: " + _num);
    25                     //通知主線程,錢已付完成
    26                     _autoReset2.Set();
    27                 }
    28             }
    29         }
    30 
    31         private static void TreadGetBookProc()
    32         {
    33             while (true)
    34             {
    35                 //_autoReset.WaitOne();
    36                 _autoReset1.WaitOne();
    37                 //lock (_getBookObj)
    38                 {
    39                     Console.WriteLine(Thread.CurrentThread.Name + ",編號: " + _num);
    40                     //通知主線程,書已取走
    41                     _autoReset3.Set();
    42                 }
    43             }
    44         }
    45 
    46 
    47         static void Main(string[] args)
    48         {
    49             //本案例是通過AutoResetEvent來實現多線程同步
    50             //購買書數量
    51             const int num = 5;
    52 
    53             //付錢線程
    54             Thread threadPayMoney = new Thread(new ThreadStart(ThreadPayMoneyProc));
    55             threadPayMoney.Name = "付錢線程";
    56             //取書線程
    57             Thread threadGetBook = new Thread(new ThreadStart(TreadGetBookProc));
    58             threadGetBook.Name = "取書線程";
    59 
    60             //開始執行線程
    61             threadPayMoney.Start();
    62             threadGetBook.Start();
    63 
    64             //主線程開始選書
    65             Console.WriteLine("----------------主線程開始選書!------------------");
    66             for (int i = 1; i <= num; i++)
    67             {
    68                 Console.WriteLine("主線程選書編號:" + i);
    69                 _num = i;
    70                 //_autoReset.Set();
    71 
    72                 //通知付錢線程
    73                 _autoReset0.Set();
    74                 //主線延時1ms執行(但不知道付錢線程這個過程需要多少時間)
    75                 //Thread.Sleep(1);
    76                 //等待付錢線程
    77                 _autoReset2.WaitOne();
    78 
    79                 //付完錢后,通知取書線程
    80                 _autoReset1.Set();
    81                 //主線延時1ms執行(但不知道取書線程這個過程需要多少時間)
    82                 //Thread.Sleep(1);
    83                 //等待取書線程
    84                 _autoReset3.WaitOne();
    85                 Console.WriteLine("-----------------------------------");
    86                 //完成后,繼續下一個任務處理
    87             }
    88 
    89             Console.ReadKey();
    90 
    91 
    92         }
    93     }
    復制代碼

    運行結果如下圖:

    運行結果和上面使用指定主線程休眠所運行結果是一樣的。但是,可以不用指定主線程休眠時間,也不需要指定。因為你沒法估計子線程所運行的時間,而且每次運行時間都不一樣。

    后話

    本例中, 買書場景其實有兩種編程結構(或者編程思想)。一種是本例中的,買書是主線程,而收銀臺(付錢線程)、倉庫(取書線程)。這兩個線程是一直存在的,一直跑著的。只要有書過來,這兩個線程就會執行。這可以聯系到現實中的收銀臺和倉庫。

    第二種編程思想,買書是一個發起線程,然后開啟一個付款線程和取書線程。這時,買書線程(主線程)可以確定這兩個子線程什么時候執行完成。使用 線程對象.Join(),執行完后,主線程接著下步任務處理。

    Copyright © 2020-2022 南京傾心軟件技術有限公司 版權所有     蘇ICP備2020070309號-1
    QQ在線咨詢
    13605185909
    返回頂部
    √天堂中文官网在线