<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      NET多線程探索-線程同步和通信

      2012-03-20 16:53  海不是藍  閱讀(2330)  評論(8)    收藏  舉報

      NET中各種線程同步方法


      在NET多線程開發中,有時候需要多個線程協調工作,完成這個步驟的過程稱為“同步”。

      使用同步的主要原因:
      1.多個線程訪問同一個共享資源。
      2.多線程寫入文件時保證只有一個線程使用文件資源。 3.由事件引發線程,線程等待事件,需要掛起線程。

      NET中線程同步常見的幾種方法:

      1.lock


      lock 確保當一個線程位于代碼的臨界區時,另一個線程不進入臨界區。如果其他線程試圖進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。
      lock的優點:簡單易用,對象的同步幾乎透明,輕量級。

      使用lock需要注意:
      鎖定的對于應該是私有的,如果是公有的對象,可能出現超出控制范圍的其它代碼鎖定該對象。
      所以應該盡量避免使用lock(this),不保證會有其他線程闖入破壞數據正確性。

      一個lock(this)錯誤的示例:

      class Program
      {
          static void Main(string[] args)
          {
              A a1 = new A();
              A a2 = new A();
              Thread T1 = new Thread(new ParameterizedThreadStart(a1.Test));
              Thread T2 = new Thread(new ParameterizedThreadStart(a2.Test));
              T1.Start(2);
              T2.Start(5);
              Console.Read();
          }
      }
      public class A
      {
          public static Int32 Count = 2;
          public void Test(object i)
          {
              lock (this)
              {
                  Console.WriteLine("Count={0}", Count);
                  Count += (Int32)i;
                  Thread.Sleep(1 * 1000);
                  Console.WriteLine("i={0},?Count+i={1}", i, Count);
                  Console.WriteLine("--------------------------");
              }
          }
      }

      圖片1
      這里數據和我們期待的不相同。

      這里lock鎖定的是A的實例,當線程T1執行的時候,lock鎖定了a1對象,所以線程t2可以執行a2對象的Test方法。

      正確的寫法:

      public class A
      {
          private static object obj = new object();
          public static Int32 Count = 2;
          public void Test(object i)
          {
              lock (obj)
              {
                  Console.WriteLine("Count={0}", Count);
                  Count += (Int32)i;
                  Thread.Sleep(1 * 1000);
                  Console.WriteLine("i={0},?Count+i={1}", i, Count);
                  Console.WriteLine("--------------------------");
              }
          }
      }

      圖片2

      這里的線程已經正常工作了,Count也正常的累加。


      lock (obj)怎么錯誤了?
      上面正常運行的程序稍微改動下!

      class Program
      {
          static void Main(string[] args)
          {
              A a1 = new A();
              A a2 = new A();
              Thread T1 = new Thread(new ParameterizedThreadStart(a1.Test));
              Thread T2 = new Thread(new ParameterizedThreadStart(a2.Test));
              T1.Start(2);
              T2.Start(5);
              Console.Read();
          }
      }
      public class A
      {
          private object obj = new object();
          public static Int32 Count = 2;
          public void Test(object i)
          {
              lock (obj)
              {
                  Console.WriteLine("Count={0}", Count);
                  Count += (Int32)i;
                  Thread.Sleep(1 * 1000);
                  Console.WriteLine("i={0},?Count+i={1}", i, Count);
                  Console.WriteLine("--------------------------");
              }
          }
      }

      圖片3

      分析下:這里我們把

      private static object obj = new object();

      中的static去掉了,所以obj變成了私有的實例成員,a1,a2都有不同的obj實例,所以lock這里也就沒什么作用了!

      讓lock不再錯下去!
      這里我們也不再把static寫上去了,只需要把調用那里稍微改動下。

      class Program
      {
          static void Main(string[] args)
          {
              A a1 = new A();
              Thread T1 = new Thread(new ParameterizedThreadStart(a1.Test));
              Thread T2 = new Thread(new ParameterizedThreadStart(a1.Test));
              T1.Start(2);
              T2.Start(5);
              Console.Read();
          }
      }

      圖片4

      我們這里讓a2對象去見馬克思了,a1對象的Test調用了2次,這里lock鎖定的obj都是a1的同一個私有對象obj,所以lock是起作用的!

       

      Monitor


      Monitor實現同步比lock復雜點,lock實際上是Monitor的簡便方式,lock最終還是編譯成Monitor。
      不同處:
      1.Monitor在使用的時候需要手動指定鎖和手動釋放手。
      2.Monitor比lock多了幾個實用的方法

      public static bool Wait(object obj);
      public static void Pulse(object obj);
      public static void PulseAll(object obj);


      Mointor同步實例:

      class Program
      {
          static void Main(string[] args)
          {
              Int32[] nums = { 1, 2, 3, 4, 5 };
              SumThread ST1 = new SumThread("Thread1");
              SumThread ST2 = new SumThread("Thread2");
              ST1.Run(nums);
              ST2.Run(nums);
              Console.Read();
          }
      }
      
      public class SumThread
      {
          //注意這里私有靜態SA是SumThread共有的,所以考慮同步問題
          private static SumArray SA = new SumArray();
          private Thread t;
      
          public SumThread(string ThreadName)
          {
              t = new Thread((object nums) =>
              {
                  Console.WriteLine("線程{0}開始執行...", t.Name);
                  Int32 i = SA.GetSum((Int32[])nums);
                  Console.WriteLine("線程{0}執行完畢,sum={1}", t.Name, i);
              });
              t.Name = ThreadName;
          }
      
          public void Run(Int32[] nums)
          {
              t.Start(nums);
          }
      }
      
      public class SumArray
      {
          private Int32 sum;
          private  object obj = new object();
      
          public Int32 GetSum(Int32[] nums)
          {
              Monitor.Enter(obj);
              try
              {
                  //初始化sum值,以免獲取到其它線程的臟數據
                  sum = 0;
                  foreach (Int32 num in nums)
                  {
                      sum += num;
                      Console.WriteLine("當前線程是:{0},sum={1}", Thread.CurrentThread.Name, sum);
                      Thread.Sleep(1 * 1000);
                  }
                  return sum;
              }
              catch (Exception e)
              {
                  Console.WriteLine(e.Message);
                  return 0;
              }
              finally
              {
                  //很重要,千萬不要忘記釋放鎖
                  Monitor.Exit(obj);
              }
          }
      }

      圖片5


      這里線程之間和藹可親的執行著,沒有去搶著計算。
      試著把

      Monitor.Enter(obj);
      Monitor.Exit(obj);

      去掉,那么線程就不會這么聽話了!

      圖片6

       

      另外一種同步的寫法

      前面使用的同步方式并不是所有情況都適合的,假如我們調用的是第三方的組件,我們沒有修改源碼的權限,那么我們只有考慮下面這種同步的實現。

      class Program
      {
          static void Main(string[] args)
          {
              Int32[] nums = { 1, 2, 3, 4, 5 };
              SumThread ST1 = new SumThread("Thread1");
              SumThread ST2 = new SumThread("Thread2");
              ST1.Run(nums);
              ST2.Run(nums);
              Console.Read();
          }
      }
      
      public class SumThread
      {
          //注意這里私有靜態SA是SumThread共2有的,所以考慮同步問題
          private static SumArray SA = new SumArray();
          private Thread t;
      
          public SumThread(string ThreadName)
          {
              t = new Thread((object nums) =>
              {
                  Console.WriteLine("線程{0}開始執行...", t.Name);
                  Monitor.Enter(SA);
                  try
                  {
                      Int32 i = SA.GetSum((Int32[])nums);
                      Console.WriteLine("線程{0}執行完畢,sum={1}", t.Name, i);
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine(e.Message);
                  }
                  finally
                  {
                      //很重要,千萬不要忘記釋放鎖
                      Monitor.Exit(SA);
                  }
              });
              t.Name = ThreadName;
          }
      
          public void Run(Int32[] nums)
          {
              t.Start(nums);
          }
      }
      
      public class SumArray
      {
          private Int32 sum;
      
          public Int32 GetSum(Int32[] nums)
          {
      
              //初始化sum值,以免獲取到其它線程的臟數據
              sum = 0;
              foreach (Int32 num in nums)
              {
                  sum += num;
                  Console.WriteLine("當前線程是:{0},sum={1}", Thread.CurrentThread.Name, sum);
                  Thread.Sleep(1 * 1000);
              }
              return sum;
          }
      }

      圖片7

      注意:這里鎖定的是SA.GetSum()調用本身,不是方法內部代碼,SA對象是私有的。

       

      Monitor-線程通信


      當線程T正在lock塊執行,需要訪問另外一個線程lock塊中的資源R,這個時候如果T等待R可用,有可能會讓線程進入死循環。
      這里就可以使用線程通信,先讓T暫時放棄對lock塊中的控制,等R變得可用,那么就通知線程T恢復運行。

      public static bool Wait(object obj);
      public static void Pulse(object obj);
      public static void PulseAll(object obj);

      上面就是這里需要用的方法,屬于Monitor。 Wait是讓線程暫停,這個方法有個重寫,多了一個參數指定暫停的毫秒數。
      Pulse是喚醒線程。
      時鐘滴答例子:

      class Program
      {
          static void Main(string[] args)
          {
              Clock C = new Clock();
              C.RunClock(1);
              Console.Read();
          }
      }
      public class Clock
      {
          private object obj = new object();
      
          //開始運行時鐘,輸入運行分鐘
          public void RunClock(Int32 Minute)
          {
              Thread T1 = new Thread((object Minute1) =>
              {
                  Int32 m = Convert.ToInt32(Minute1) * 60 / 2;
                  while (m > 0)
                  {
                      DI(true);
      
                      m--;
                  }
              });
              Thread T2 = new Thread((object Minute1) =>
              {
                  Int32 m = Convert.ToInt32(Minute1) * 60 / 2;
                  while (m > 0)
                  {
                      DA(true);
                      m--;
                  }
              });
              T1.Start(Minute);
              T2.Start(Minute);
          }
      
          public void DI(bool run)
          {
              lock (obj)
              {
                  Console.WriteLine("嘀");
                  Thread.Sleep(1000);
                  Monitor.Pulse(obj);//執行完畢,喚醒其它線程
                  Monitor.Wait(obj);//進入暫停,移交執行權利,等待喚醒
              }
          }
      
          public void DA(bool run)
          {
              lock (obj)
              {
                  Console.WriteLine("嗒");
                  Thread.Sleep(1000);
                  Monitor.Pulse(obj);//執行完畢,喚醒其它線程
                  Monitor.Wait(obj);//進入暫停,移交執行權利,等待喚醒
              }
          }
      }

      圖片8

       

      謝謝Shikyoh指出錯誤,已經修改

      就寫到這里,下一篇寫下互斥鎖信號量這些。

       

      作者:海不是藍
      博客:hailan2012
      郵箱:hailan2012@sina.com
      本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

      主站蜘蛛池模板: 性色在线视频精品| 久久久精品2019中文字幕之3| 欧美牲交a免费| 亚洲精品久荜中文字幕| 好湿好紧太硬了我太爽了视频| 日韩精品专区在线影观看| 国产不卡在线一区二区| 亚欧洲乱码视频在线专区| 大陆精大陆国产国语精品| 午夜通通国产精品福利| 国产精品视频免费一区二区三区| 91毛片网| 国产精品一区在线蜜臀| 成人啪啪高潮不断观看| 国产一区韩国主播| 好吊视频一区二区三区人妖| 国产肥臀视频一区二区三区| 小13箩利洗澡无码视频网站| 欧美不卡无线在线一二三区观| 精品国产综合一区二区三区 | 国产欧美日韩免费看AⅤ视频| 9999国产精品欧美久久久久久| 美腿丝袜亚洲综合在线视频| 久久国产成人av蜜臀| 欧美激情一区二区三区成人| 国产无遮挡又黄又爽不要vip软件 国产成人精品一区二区秒拍1o | 色老99久久精品偷偷鲁| 黔东| 国产一级老熟女自拍视频| 国产中文字幕精品在线| 国产综合色产在线视频欧美 | 六月丁香婷婷色狠狠久久| 91精品亚洲一区二区三区| 人妻少妇久久久久久97人妻| 亚洲aⅴ无码专区在线观看q| 米易县| 18禁一区二区每日更新| 国产伦精品一区二区三区妓女下载| 亚洲精品成人区在线观看| 亚洲日韩性欧美中文字幕| 一区二区三区激情都市|