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

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

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

      多線程中的鎖系統(tǒng)(一)-基礎(chǔ)用法

           平常在多線程開發(fā)中,總避免不了線程同步。本篇對net多線程中的鎖系統(tǒng)做個簡單描述。

      閱讀目錄:

      1. lock、Monitor
      2. 作用域范圍
      3. 字符串鎖
      4. Monitor的用法
      5. Mutex
      6. Semaphore
      7. 總結(jié)

      lock、Monitor

      Lock是Monitor語法糖簡化寫法,Lock在IL會生成Monitor。

             //======Example 1=====
                  string obj = "helloworld";
                  lock (obj)
                  {
                      Console.WriteLine(obj);
                  }
                  //lock  IL會編譯成如下寫法
                  bool isGetLock = false;
                  Monitor.Enter(obj, ref isGetLock);
                  try
                  {
                      Console.WriteLine(obj);
                  }
                  finally
                  {
                      if (isGetLock)
                      {
                          Monitor.Exit(obj);
                      }
                  }

      isGetLock參數(shù)是Framework  4.0后新加的。 為了使程序在所有情況下都能夠確定,是否有必要釋放鎖。例: Monitor.Enter拿不到鎖

      Monitor.Enter 是可以鎖值類型的。鎖時會裝箱成新對象,所以無法做到線程同步。

      作用域范圍

           一:Lock是只能在進(jìn)程內(nèi)鎖,不能跨進(jìn)程,內(nèi)部走的是混合構(gòu)造,先自旋再轉(zhuǎn)成內(nèi)核構(gòu)造。

           二:關(guān)于對type類型的鎖,如下:

         //======Example 2=====
                  new Thread(new ThreadStart(() => {
                      lock (typeof(int))
                      {
                          Thread.Sleep(10000);
                          Console.WriteLine("Thread1釋放");
                      }
                  })).Start();
                  Thread.Sleep(1000);
                  lock(typeof(int))
                  {
                      Console.WriteLine("Thread2釋放");
                  }

      運行結(jié)果如下:

      在看個例子:

        //======Example 3=====
                  Console.WriteLine(DateTime.Now);
                  AppDomain appDomain1 = AppDomain.CreateDomain("AppDomain1");
                  LockTest Worker1 = (LockTest)appDomain1.CreateInstanceAndUnwrap(
                   Assembly.GetExecutingAssembly().FullName,
                   "ConsoleApplication1.LockTest");
                  Worker1.Run();
      
                  AppDomain appDomain2 = AppDomain.CreateDomain("AppDomain2");
                  LockTest Worker2 = (LockTest)appDomain2.CreateInstanceAndUnwrap(
                  Assembly.GetExecutingAssembly().FullName,
                  "ConsoleApplication1.LockTest");
                  Worker2.Run();
      /// <summary>
          /// 跨應(yīng)用程序域邊界或遠(yuǎn)程訪問時需要繼承MarshalByRefObject
          /// </summary>
          public class LockTest : MarshalByRefObject
          {
              public void Run()
              {
                  lock (typeof(int))
                  {
                      Thread.Sleep(10000);
                      Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + ": Thread 釋放," + DateTime.Now);
                  }
              }
          }

      運行結(jié)果如下:

      第一個例子說明,在同進(jìn)程同域,不同線程下,鎖type int,其實鎖的是同一個int對象,所以要慎用。

      第二個例子,這里就簡單說下。

            A: CLR啟動時,會創(chuàng)建 系統(tǒng)域(System Domain)和共享域(Shared Domain), 默認(rèn)程序域(Default AppDomain)。 系統(tǒng)域和共享域是單例的。程序域可以有多個,例子中我們使用AppDomain.CreateDomain方法創(chuàng)建的。

            B:  按正常來說,每個程序域的代碼都是隔離,互不影響的。但對于一些基礎(chǔ)類型來說,每個程序域都重新加載一份,就顯得有點浪費,帶來額外的損耗壓力。聰明的CLR會把一些基本類型Object, ValueType, Array, Enum, String, and Delegate等所在的程序集MSCorLib.dll,在CLR啟動過程中都會加載到共享域。  每個程序域都會使用共享域的基礎(chǔ)類型實例。  

            C: 而每個程序域都有屬于自己的托管堆。托管堆中最重要的是GC heap和Loader heap。GC heap用于引用類型實例的存儲,生命周期管理和垃圾回收。Loader heap保存類型系統(tǒng),如MethodTable,數(shù)據(jù)結(jié)構(gòu)等,Loader heap生命周期不受GC管理,跟程序域卸載有關(guān)。

           所以共享域中Loader heap MSCorLib.dll中的int實例會一直保留著,直到進(jìn)程結(jié)束。單個程序域卸載也不受影響。作用域很大有沒有!!!

           這時第二個例子也很容易理解了。 鎖int實例是跨程序域的,MSCorLib中的基礎(chǔ)類型都是這樣, 極容易造成死鎖。  而自定義類型則會加載到自己的程序域,不會影響其他。

      字符串的鎖

      我們都知道鎖的目的,是為了多線程下值被破壞。也知道string在c#是個特殊對象,值是不變的,每次變動都是一個新對象值,這也是推薦stringbuilder原因。如例:

          //======Example 4=====
                  string str1 = "mushroom";
                  string str2 = "mushroom";
                  var result1 = object.ReferenceEquals(str1, str2);
                  var result2 = object.ReferenceEquals(str1, "mushroom");
                  Console.WriteLine(result1 + "-" + result2);
                  /* output
                   * True-True
                   */

       正是由于c#中字符串的這種特性,所以字符串是在多線程下是不會被修改的,只讀的。它存在于SystemDomain域中managed heap中的一個hash table中。其中Key為string本身,Value為string對象的地址。

       當(dāng)程序域需要一個string的時候,CLR首先在這個Hashtable根據(jù)這個string的hash code試著找對應(yīng)的Item。如果成功找到,則直接把對應(yīng)的引用返回,否則就在SystemDomain對應(yīng)的managed heap中創(chuàng)建該 string,并加入到hash table中,并把引用返回。所以說字符串的生命周期是基于整個進(jìn)程的,也是跨AppDomain。

      Monitor的用法

      簡單介紹下Wait,Pulse,PulseAll的用法,已加注釋。

       static string str = "mushroom";
              static void Main(string[] args)
              {
                  new Thread(() =>
                  {
                      bool isGetLock = false;
                      Monitor.Enter(str, ref isGetLock);
                      try
                      {
                          Console.WriteLine("Thread1第一次獲取鎖");
                          Thread.Sleep(5000);
                          Console.WriteLine("Thread1暫時釋放鎖,并等待其他線程釋放通知信號。");
                          Monitor.Wait(str); 
                          Console.WriteLine("Thread1接到通知,第二次獲取鎖。");
                          Thread.Sleep(1000);
                      } 
                      finally
                      {
                          if (isGetLock)
                          {
                              Monitor.Exit(str);
                              Console.WriteLine("Thread1釋放鎖");
                          }
                      }
                  }).Start();
                  Thread.Sleep(1000);
                  new Thread(() =>
                  {
                      bool isGetLock = false;
                      Monitor.Enter(str, ref isGetLock); //一直等待中,直到其他釋放。
                      try
                      {
                          Console.WriteLine("Thread2獲得鎖");
                          Thread.Sleep(5000);
                          Monitor.Pulse(str); //通知隊列里一個線程,改變鎖狀態(tài)。  Pulseall 通知所有的
                          Console.WriteLine("Thread2通知其他線程,改變狀態(tài)。");
                          Thread.Sleep(1000);
                      }
                      finally
                      {
                          if (isGetLock)
                          {
                              Monitor.Exit(str);
                              Console.WriteLine("Thread2釋放鎖");
                          }
                      }
      
                  }).Start();
                  Console.ReadLine();

      Mutex

       lock是不能跨進(jìn)程鎖的。 mutex作用和lock類似,但是它能跨進(jìn)程鎖資源(走的是windows內(nèi)核構(gòu)造),如例子:

          static bool createNew = false;
              //第一個參數(shù) 是否應(yīng)擁有互斥體的初始所屬權(quán)。即createNew true時,mutex默認(rèn)獲得處理信號
              //第二個是名字,第三個是否成功。
              public static Mutex mutex = new Mutex(true, "mushroom.mutex", out createNew);
      
              static void Main(string[] args)
              {
                  //======Example 5=====
                  if (createNew)  //第一個創(chuàng)建成功,這時候已經(jīng)拿到鎖了。 無需再WaitOne了。一定要注意。
                  {
                      try
                      {
                          Run();
                      }
                      finally
                      {
                          mutex.ReleaseMutex(); //釋放當(dāng)前鎖。  
                      }
                  }
                  //WaitOne 函數(shù)作用是阻止當(dāng)前線程,直到拿到收到其他實例釋放的處理信號。
                  //第一個參數(shù)是等待超時時間,第二個是否退出上下文同步域。
                  else if (mutex.WaitOne(10000,false))//
                  {
                      try
                      {
                          Run();
                      }
                      finally
                      {
                          mutex.ReleaseMutex();
                      }
                  }
                  else//如果沒有發(fā)現(xiàn)處理信號
                  {
                      Console.WriteLine("已經(jīng)有實例了。");
                      Console.ReadLine();
                  }
              }
              static void Run()
              {
                  Console.WriteLine("實例1");
                  Console.ReadLine();
              }

      順序啟動A  B實例測試下。A首先拿到鎖,輸出 實例1 。B在等待, 如果10秒內(nèi)A釋放,B拿到執(zhí)行Run()。超時后輸出"已經(jīng)有實例了"。

      這里注意的是第一個拿到處理信號 的實例,已經(jīng)拿到鎖了。不需要再WaitOne。  否則報異常。  

      Semaphore

       即信號量,我們可以把它理解為升級版的mutex。mutex對一個資源進(jìn)行鎖,semaphore則是對多個資源進(jìn)行加鎖。

      semaphore是由windows內(nèi)核維持一個int32變量的線程計數(shù)器,線程每調(diào)用一次、計數(shù)器減一、釋放后對應(yīng)加一, 超出的線程則排隊等候。

      走的是內(nèi)核構(gòu)造,所以semaphore也是可以跨進(jìn)程的。

       static void Main(string[] args)
              {
                  Console.WriteLine("準(zhǔn)備處理隊列");
      
                  bool createNew = false;
      
                  SemaphoreSecurity ss = new SemaphoreSecurity(); //信號量權(quán)限控制
                  Semaphore semaphore = new Semaphore(2, 2, "mushroom.Semaphore", out createNew,null);
                  for (int i = 1; i <= 5; i++)
                  {
                      new Thread((arg) =>
                      {
                          semaphore.WaitOne();
                          Console.WriteLine(arg + "處理中");
                          Thread.Sleep(10000);
                          semaphore.Release(); //即semaphore.Release(1)
                          //semaphore.Release(5);可以釋放多個,但不能超過最大值。如果最后釋放的總量超過本身總量,也會報錯。 不建議使用
      
                      }).Start(i);
                  }
                  Console.ReadLine();
              }

      總結(jié)

      mutex、Semaphore  需要先把托管代碼轉(zhuǎn)成本地用戶模式代碼、再轉(zhuǎn)換成本地內(nèi)核代碼。  

      當(dāng)釋放后需要重新轉(zhuǎn)換成托管代碼,性能會有一定的損耗,所以盡量在需要跨進(jìn)程的場景再使用。 

      參考 http://www.rzrgm.cn/artech/archive/2007/06/04/769805.html

      posted @ 2014-12-21 22:55  蘑菇先生  閱讀(21589)  評論(7)    收藏  舉報
      主站蜘蛛池模板: 久久中文字幕av第二页| 性视频一区| 久久天天躁夜夜躁狠狠躁2022| 欧美日韩视频综合一区无弹窗| 精品久久久中文字幕人妻| 午夜免费福利小电影| 国产寡妇偷人在线观看| 亚洲精品成人一二三专区| 日韩狼人精品在线观看| 国产人妻无码一区二区三区18| 久久精品国产99久久无毒不卡| 内地自拍三级在线观看| 国产精品免费视频不卡| 成人网站av亚洲国产| 最新偷拍一区二区三区| 五月花成人网| 亚洲熟妇色xxxxx亚洲| 亚洲人成电影网站色mp4| 中文国产成人精品久久不卡| 白水县| 午夜大片免费男女爽爽影院| 丰满人妻跪趴高撅肥臀| 亚洲国产无线乱码在线观看| 欧美人与动牲交精品| 欧美、另类亚洲日本一区二区| 午夜精品福利一区二区三| 欧美疯狂xxxxxbbbbb| 亚洲成a人无码av波多野| 性欧美三级在线观看| 亚洲国产中文在线有精品| 国产色婷婷精品综合在线| 国产蜜臀av在线一区在线| 四虎国产精品永久入口| 国产精品国产三级国快看| 久久日韩在线观看视频| 九九热在线精品视频99| 亚洲理论在线A中文字幕| 日韩精品亚洲专在线电影| 国产成人亚洲综合图区| 精品无码久久久久久尤物| 亚洲日韩国产精品第一页一区|